Appearance
全局过滤器
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 | 路由目标 URI | lb://user-service |
outcome | 请求结果分类 | SUCCESS, CLIENT_ERROR |
status | HTTP 状态码 | 200, 404, 500 |
httpMethod | HTTP 方法 | 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 # 缓存存活时间缓存触发条件
响应会被缓存当满足以下所有条件时:
- 请求类型:无请求体的 GET 请求
- 响应状态码:200 (OK)、206 (Partial Content)、301 (Moved Permanently)
- 缓存控制头:允许缓存(没有
no-store或private)
自定义缓存管理器
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-config4. 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 | 目标请求 URL | URL 转换处理 |
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 的全局过滤器为微服务架构提供了强大的横切关注点处理能力。通过合理使用内置过滤器和自定义过滤器,可以实现:
- ✅ 统一的安全控制:认证、授权、限流
- ✅ 完善的监控体系:指标收集、性能监控、异常处理
- ✅ 优化的性能表现:响应缓存、连接池管理
- ✅ 灵活的路由策略:负载均衡、故障转移
在设计全局过滤器时,要注意过滤器的执行顺序和性能影响。建议将轻量级的过滤器放在前面,重量级的处理放在后面,并合理使用异步编程模型来避免阻塞。