Skip to content

全局过滤器

Spring Cloud Gateway 的全局过滤器是一种特殊的过滤器,它会有条件地应用于所有路由。全局过滤器与网关过滤器具有相同的方法签名,为微服务架构提供了强大的横切关注点处理能力。

核心概念

什么是全局过滤器?

全局过滤器是应用于网关所有路由的过滤器组件,用于处理跨路由的通用逻辑,如:

  • 统一的安全认证
  • 请求日志记录
  • 指标收集
  • 响应缓存
  • 负载均衡

全局过滤器解决的问题

在微服务架构中,每个请求都需要经过一些通用的处理逻辑:

全局过滤器与网关过滤器的执行顺序

当请求匹配到路由时,过滤 Web 处理器会将所有 GlobalFilter 实例和路由特定的 GatewayFilter 实例添加到过滤器链中。这个组合的过滤器链通过 org.springframework.core.Ordered 接口进行排序。

过滤器执行阶段

Spring Cloud Gateway 区分过滤器逻辑的执行阶段:

  • "pre" 阶段:优先级最高的过滤器首先执行
  • "post" 阶段:优先级最高的过滤器最后执行
kotlin
@Component
class CustomGlobalFilter : GlobalFilter, Ordered {

    private val logger = LoggerFactory.getLogger(CustomGlobalFilter::class.java)

    /**
     * 过滤器核心逻辑
     * @param exchange 服务器 Web 交换对象,包含请求和响应信息
     * @param chain 过滤器链,用于传递请求到下一个过滤器
     * @return Mono<Void> 异步响应
     */
    override fun filter(exchange: ServerWebExchange, chain: GatewayFilterChain): Mono<Void> {
        logger.info("执行自定义全局过滤器 - Pre 阶段")

        // Pre 阶段逻辑:在请求转发到下游服务之前执行
        val startTime = System.currentTimeMillis()
        exchange.attributes["startTime"] = startTime

        // 继续执行过滤器链
        return chain.filter(exchange)
            .doFinally {
                // Post 阶段逻辑:在响应返回给客户端之前执行
                val endTime = System.currentTimeMillis()
                val duration = endTime - startTime
                logger.info("请求处理完成,耗时: ${duration}ms")
            }
    }

    /**
     * 定义过滤器执行顺序
     * 数值越小,优先级越高
     */
    override fun getOrder(): Int = -1
}

@Configuration
class FilterConfiguration {

    /**
     * 注册自定义全局过滤器为 Bean
     */
    @Bean
    fun customGlobalFilter(): GlobalFilter = CustomGlobalFilter()
}

内置全局过滤器详解

1. 网关指标过滤器 (Gateway Metrics Filter)

指标过滤器用于监控网关的性能和健康状况,这在生产环境中至关重要。

启用指标收集

kotlin
// 添加依赖
dependencies {
    implementation("org.springframework.boot:spring-boot-starter-actuator")
    implementation("io.micrometer:micrometer-registry-prometheus") // 可选:Prometheus 支持
}

配置指标收集

yaml
spring:
  cloud:
    gateway:
      metrics:
        enabled: true # 启用指标收集(默认为 true)
        tags:
          path:
            enabled: true # 启用路径标签(默认为 false)

指标标签说明

指标过滤器会为每个请求添加以下标签:

标签名描述示例值
routeId路由标识user-service
routeUri路由目标 URIlb://user-service
outcome请求结果分类SUCCESS, CLIENT_ERROR
statusHTTP 状态码200, 404, 500
httpMethodHTTP 方法GET, POST
path请求路径(可选)/api/users

业务场景示例

kotlin
@RestController
@RequestMapping("/admin/metrics")
class MetricsController {

    @Autowired
    private lateinit var meterRegistry: MeterRegistry

    /**
     * 获取网关请求指标统计
     */
    @GetMapping("/gateway-stats")
    fun getGatewayStats(): Map<String, Any> {
        val timer = Timer.Sample.start(meterRegistry)

        // 获取指标数据
        val metrics = meterRegistry.find("spring.cloud.gateway.requests")
            .timers()
            .associate { timer ->
                val tags = timer.id.tags.associate { it.key to it.value }
                "${tags["routeId"]}-${tags["httpMethod"]}" to mapOf(
                    "count" to timer.count(),
                    "totalTime" to timer.totalTime(TimeUnit.MILLISECONDS),
                    "meanTime" to timer.mean(TimeUnit.MILLISECONDS)
                )
            }

        return mapOf(
            "timestamp" to Instant.now(),
            "metrics" to metrics
        )
    }
}

2. 本地响应缓存过滤器 (Local Response Cache Filter)

本地缓存过滤器使用 Caffeine 缓存库来缓存响应,显著提高重复请求的响应速度。

启用缓存过滤器

kotlin
// 添加依赖
dependencies {
    implementation("com.github.ben-manes.caffeine:caffeine")
    implementation("org.springframework.boot:spring-boot-starter-cache")
}

配置缓存策略

yaml
spring:
  cloud:
    gateway:
      global-filter:
        local-response-cache:
          enabled: true # 启用全局缓存
      filter:
        local-response-cache:
          enabled: true # 启用路由级缓存
          size: 10MB # 缓存大小限制
          time-to-live: 5m # 缓存存活时间

缓存触发条件

响应会被缓存当满足以下所有条件时:

  1. 请求类型:无请求体的 GET 请求
  2. 响应状态码:200 (OK)、206 (Partial Content)、301 (Moved Permanently)
  3. 缓存控制头:允许缓存(没有 no-storeprivate

自定义缓存管理器

kotlin
@Configuration
class CacheConfiguration {

    /**
     * 自定义缓存管理器
     * 如果项目中有多个 CacheManager,需要使用 @Primary 或 @Qualifier
     */
    @Bean
    @Primary
    fun caffeineCacheManager(): CacheManager {
        val cacheManager = CaffeineCacheManager()

        // 配置缓存规格
        cacheManager.setCaffeine(
            Caffeine.newBuilder()
                .initialCapacity(100) // 初始容量
                .maximumSize(1000) // 最大条目数
                .expireAfterWrite(Duration.ofMinutes(10)) // 写入后过期时间
                .recordStats() // 启用统计
        )

        return cacheManager
    }

    /**
     * 缓存统计监控
     */
    @EventListener
    fun handleCacheStats(event: ApplicationReadyEvent) {
        // 定期输出缓存统计信息
        Executors.newScheduledThreadPool(1).scheduleAtFixedRate({
            val cache = caffeineCacheManager().getCache("responseCache")
            if (cache is CaffeineCache) {
                val stats = cache.nativeCache.stats()
                println("缓存统计: 命中率=${stats.hitRate()}, 驱逐数=${stats.evictionCount()}")
            }
        }, 0, 30, TimeUnit.SECONDS)
    }
}

如果项目中创建了自定义的 `CacheManager` beans,需要使用 `@Primary` 标记或通过 `@Qualifier` 注入。

3. 转发路由过滤器 (Forward Routing Filter)

转发路由过滤器用于处理本地转发请求,适用于需要在网关内部处理的场景。

使用场景

kotlin
@RestController
@RequestMapping("/local")
class LocalController {

    /**
     * 本地端点处理器
     * 可以处理一些轻量级的业务逻辑,如健康检查、配置获取等
     */
    @GetMapping("/health")
    fun healthCheck(): Map<String, Any> {
        return mapOf(
            "status" to "UP",
            "timestamp" to Instant.now(),
            "gateway" to "Spring Cloud Gateway",
            "version" to "1.0.0"
        )
    }

    @GetMapping("/config")
    fun getConfig(): Map<String, Any> {
        return mapOf(
            "maxRequestSize" to "10MB",
            "timeout" to "30s",
            "circuitBreaker" to "enabled"
        )
    }
}

路由配置

yaml
spring:
  cloud:
    gateway:
      routes:
        - id: local-health-route
          uri: forward:///local/health # 转发到本地端点
          predicates:
            - Path=/health
        - id: local-config-route
          uri: forward:///local/config
          predicates:
            - Path=/gateway-config

4. Netty 路由过滤器 (Netty Routing Filter)

Netty 路由过滤器是网关的核心组件,负责将请求代理到下游服务。

工作原理

自定义 HttpClient 配置

kotlin
@Configuration
class HttpClientConfiguration {

    /**
     * 自定义 HttpClient 配置
     */
    @Bean
    fun httpClientCustomizer(): HttpClientCustomizer {
        return HttpClientCustomizer { httpClient ->
            httpClient
                .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 5000) // 连接超时
                .option(ChannelOption.SO_KEEPALIVE, true) // 保持连接
                .doOnConnected { connection ->
                    // 配置读写超时
                    connection.addHandlerLast(ReadTimeoutHandler(30, TimeUnit.SECONDS))
                    connection.addHandlerLast(WriteTimeoutHandler(30, TimeUnit.SECONDS))
                }
        }
    }
}

5. 响应式负载均衡过滤器 (ReactiveLoadBalancerClientFilter)

负载均衡过滤器与服务发现组件集成,实现请求的智能分发。

配置负载均衡

yaml
spring:
  cloud:
    gateway:
      routes:
        - id: user-service-route
          uri: lb://user-service # lb:// 前缀触发负载均衡
          predicates:
            - Path=/api/users/**
          filters:
            - StripPrefix=2 # 移除路径前缀
      loadbalancer:
        use404: true # 服务不可用时返回 404 而不是 503

自定义负载均衡策略

kotlin
@Configuration
class LoadBalancerConfiguration {

    /**
     * 自定义负载均衡器
     * 可以实现不同的负载均衡算法
     */
    @Bean
    @LoadBalancerClient(name = "user-service")
    fun userServiceLoadBalancer(): ReactorServiceInstanceLoadBalancer {
        return object : ReactorServiceInstanceLoadBalancer {
            override fun choose(request: Request<RequestDataContext>): Mono<Response<ServiceInstance>> {
                return loadBalancerClientFactory
                    .getInstance("user-service")
                    .get(ServiceInstanceListSupplier::class.java)
                    .next()
                    .map { instances ->
                        // 自定义选择逻辑:例如基于响应时间的选择
                        val selectedInstance = selectByResponseTime(instances)
                        DefaultResponse(selectedInstance)
                    }
            }

            private fun selectByResponseTime(instances: List<ServiceInstance>): ServiceInstance {
                // 实现基于响应时间的负载均衡逻辑
                return instances.minByOrNull {
                    // 获取实例的平均响应时间(需要自己维护统计信息)
                    getAverageResponseTime(it)
                } ?: instances.first()
            }

            private fun getAverageResponseTime(instance: ServiceInstance): Long {
                // 从缓存或监控系统获取平均响应时间
                return 100L // 示例值
            }
        }
    }
}

6. WebSocket 路由过滤器 (WebSocket Routing Filter)

WebSocket 路由过滤器支持 WebSocket 协议的代理转发。

WebSocket 路由配置

yaml
spring:
  cloud:
    gateway:
      routes:
        # WebSocket 路由
        - id: websocket-route
          uri: ws://localhost:8081 # WebSocket 目标地址
          predicates:
            - Path=/websocket/**
        # SockJS 回退路由
        - id: sockjs-route
          uri: http://localhost:8081
          predicates:
            - Path=/websocket/info/**
        # 负载均衡的 WebSocket
        - id: websocket-lb-route
          uri: lb:ws://chat-service
          predicates:
            - Path=/chat/**

WebSocket 处理器示例

kotlin
@Component
class WebSocketHandler : org.springframework.web.reactive.socket.WebSocketHandler {

    private val logger = LoggerFactory.getLogger(WebSocketHandler::class.java)

    override fun handle(session: WebSocketSession): Mono<Void> {
        logger.info("WebSocket 连接建立: ${session.id}")

        // 处理接收到的消息
        val input = session.receive()
            .map { message ->
                val payload = message.payloadAsText
                logger.info("收到消息: $payload")

                // 处理业务逻辑
                processMessage(payload)
            }
            .then()

        // 发送消息
        val output = session.send(
            Flux.interval(Duration.ofSeconds(5))
                .map { i ->
                    session.textMessage("心跳消息 $i")
                }
        )

        return Mono.zip(input, output).then()
    }

    private fun processMessage(payload: String): String {
        // 实现消息处理逻辑
        return "处理结果: $payload"
    }
}

交换标记和状态管理

路由状态标记

网关使用交换属性来跟踪请求的处理状态:

kotlin
@Component
class RouteStatusFilter : GlobalFilter, Ordered {

    override fun filter(exchange: ServerWebExchange, chain: GatewayFilterChain): Mono<Void> {
        // 检查请求是否已经被路由
        if (ServerWebExchangeUtils.isAlreadyRouted(exchange)) {
            return chain.filter(exchange)
        }

        // 执行路由逻辑
        return chain.filter(exchange)
            .doFinally {
                // 标记请求已被路由
                ServerWebExchangeUtils.setAlreadyRouted(exchange)
            }
    }

    override fun getOrder(): Int = 0
}

常用交换属性

属性名描述用途
GATEWAY_ROUTE_ATTR当前匹配的路由对象路由信息传递
GATEWAY_REQUEST_URL_ATTR目标请求 URLURL 转换处理
GATEWAY_ORIGINAL_REQUEST_URL_ATTR原始请求 URL 列表请求追踪
CLIENT_RESPONSE_ATTR客户端响应对象响应处理

最佳实践

1. 过滤器顺序规划

kotlin
object FilterOrder {
    const val AUTHENTICATION = -100     // 认证过滤器:最高优先级
    const val AUTHORIZATION = -90       // 授权过滤器
    const val RATE_LIMITING = -80       // 限流过滤器
    const val LOGGING = -70            // 日志过滤器
    const val METRICS = -60            // 指标过滤器
    const val CACHING = -50            // 缓存过滤器
    const val CUSTOM_BUSINESS = 0      // 自定义业务过滤器
}

2. 异常处理

kotlin
@Component
class GlobalExceptionFilter : GlobalFilter, Ordered {

    override fun filter(exchange: ServerWebExchange, chain: GatewayFilterChain): Mono<Void> {
        return chain.filter(exchange)
            .onErrorResume { throwable ->
                handleException(exchange, throwable)
            }
    }

    private fun handleException(exchange: ServerWebExchange, throwable: Throwable): Mono<Void> {
        val response = exchange.response
        response.statusCode = when (throwable) {
            is TimeoutException -> HttpStatus.REQUEST_TIMEOUT
            is ConnectException -> HttpStatus.BAD_GATEWAY
            else -> HttpStatus.INTERNAL_SERVER_ERROR
        }

        val errorResponse = mapOf(
            "error" to throwable.message,
            "timestamp" to Instant.now(),
            "path" to exchange.request.uri.path
        )

        val buffer = response.bufferFactory().wrap(
            ObjectMapper().writeValueAsBytes(errorResponse)
        )

        return response.writeWith(Mono.just(buffer))
    }

    override fun getOrder(): Int = -1000 // 最高优先级,确保异常被捕获
}

3. 性能监控

kotlin
@Component
class PerformanceMonitorFilter : GlobalFilter, Ordered {

    private val meterRegistry: MeterRegistry by lazy {
        Metrics.globalRegistry
    }

    override fun filter(exchange: ServerWebExchange, chain: GatewayFilterChain): Mono<Void> {
        val timer = Timer.Sample.start(meterRegistry)
        val startTime = System.nanoTime()

        return chain.filter(exchange)
            .doFinally { _ ->
                timer.stop(Timer.builder("gateway.request.duration")
                    .tag("route", getRouteId(exchange))
                    .tag("method", exchange.request.method.name())
                    .register(meterRegistry))

                val duration = Duration.ofNanos(System.nanoTime() - startTime)
                if (duration > Duration.ofMillis(1000)) {
                    logger.warn("慢请求检测: {}ms - {}",
                              duration.toMillis(),
                              exchange.request.uri)
                }
            }
    }

    private fun getRouteId(exchange: ServerWebExchange): String {
        return exchange.getAttribute<Route>(ServerWebExchangeUtils.GATEWAY_ROUTE_ATTR)
            ?.id ?: "unknown"
    }

    override fun getOrder(): Int = FilterOrder.METRICS
}

总结

Spring Cloud Gateway 的全局过滤器为微服务架构提供了强大的横切关注点处理能力。通过合理使用内置过滤器和自定义过滤器,可以实现:

  • 统一的安全控制:认证、授权、限流
  • 完善的监控体系:指标收集、性能监控、异常处理
  • 优化的性能表现:响应缓存、连接池管理
  • 灵活的路由策略:负载均衡、故障转移

在设计全局过滤器时,要注意过滤器的执行顺序和性能影响。建议将轻量级的过滤器放在前面,重量级的处理放在后面,并合理使用异步编程模型来避免阻塞。