全局过滤器
GlobalFilter 接口与 GatewayFilter 具有相同的签名。这些是特殊过滤器,有条件地应用于所有路由。
此接口及其使用方式在未来的里程碑版本中可能会发生变化。
全局过滤器与 GatewayFilter 的组合排序
当一个请求匹配到路由时,过滤网络处理器会将所有 GlobalFilter 实例以及所有路由特定的 GatewayFilter 实例添加到一个过滤器链中。这个组合后的过滤器链会按照 org.springframework.core.Ordered 接口进行排序,你可以通过实现 getOrder() 方法来设置排序顺序。
由于 Spring Cloud Gateway 在过滤器逻辑执行上区分“pre”和“post”两个阶段(参见工作原理),优先级最高的过滤器在“pre”阶段最先执行,在“post”阶段最后执行。
以下配置了一个过滤器链:
@Bean
public GlobalFilter customFilter() {
return new CustomGlobalFilter();
}
public class CustomGlobalFilter implements GlobalFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
log.info("custom global filter");
return chain.filter(exchange);
}
@Override
public int getOrder() {
return -1;
}
}
网关指标过滤器
要启用网关指标,请将 spring-boot-starter-actuator 添加为项目依赖。然后,只要 spring.cloud.gateway.metrics.enabled 属性未设置为 false,网关指标过滤器就会默认运行。此过滤器会添加一个名为 spring.cloud.gateway.requests 的计时器指标,并附带以下标签:
-
routeId: 路由ID。 -
routeUri: API路由到的URI。 -
outcome: 结果,由 HttpStatus.Series 分类。 -
status: 返回给客户端的请求HTTP状态。 -
httpStatusCode: 返回给客户端的请求HTTP状态码。 -
httpMethod: 请求使用的HTTP方法。
此外,通过 spring.cloud.gateway.server.webflux.metrics.path-tags.enabled 属性(默认为 false),你可以激活一个带有路径标签的额外指标:
path: 请求的路径。
属性 spring.cloud.gateway.server.webflux.metrics.tags.path.enabled 同样会添加上述指标,但会产生将值作为标签的副作用。此属性已被弃用,并将在未来的版本中移除。
要启用 Prometheus 端点,请将 micrometer-registry-prometheus 添加为项目依赖项。
本地响应缓存过滤器
如果启用了相关属性,LocalResponseCache 就会运行:
-
spring.cloud.gateway.global-filter.local-response-cache.enabled: 为所有路由启用全局缓存 -
spring.cloud.gateway.filter.local-response-cache.enabled: 启用关联过滤器以在路由级别使用
此功能为所有符合以下条件的响应启用基于 Caffeine 的本地缓存:
-
该请求是一个无请求体的 GET 请求。
-
响应具有以下状态码之一:HTTP 200 (OK)、HTTP 206 (Partial Content) 或 HTTP 301 (Moved Permanently)。
-
HTTP
Cache-Control标头允许缓存(这意味着它不包含以下任何值:请求中存在no-store,或响应中存在no-store或private)。
它接受两个配置参数:
-
spring.cloud.gateway.filter.local-response-cache.size: 设置此路由缓存的最大容量,用于淘汰缓存条目(单位:KB、MB 和 GB)。 -
spring.cloud.gateway.filter.local-response-cache.time-to-live设置缓存条目的过期时间(以 s 表示秒,m 表示分钟,h 表示小时)。
如果这些参数均未配置但启用了全局过滤器,默认情况下,它会为缓存的响应配置5分钟的生存时间。
此过滤器还实现了对 HTTP Cache-Control 头中 max-age 值的自动计算。如果原始响应中存在 max-age,该值将根据 timeToLive 配置参数中设置的秒数进行重写。在后续调用中,此值将根据响应到期前的剩余秒数重新计算。
将 spring.cloud.gateway.global-filter.local-response-cache.enabled 设置为 false 会为所有路由停用本地响应缓存,而 LocalResponseCache 过滤器 允许在路由级别使用此功能。
要启用此功能,请将 com.github.ben-manes.caffeine:caffeine 和 spring-boot-starter-cache 添加为项目依赖项。
如果你的项目创建了自定义的 CacheManager bean,则需要使用 @Primary 进行标记,或者通过 @Qualifier 进行注入。
转发路由过滤器
ForwardRoutingFilter 会在交换属性 ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR 中查找 URI。如果 URL 具有 forward 方案(例如 forward:///localendpoint),它会使用 Spring 的 DispatcherHandler 来处理请求。请求 URL 的路径部分会被转发 URL 中的路径覆盖。未修改的原始 URL 会被附加到 ServerWebExchangeUtils.GATEWAY_ORIGINAL_REQUEST_URL_ATTR 属性中的列表里。
Netty 路由过滤器
当 ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR 交换属性中的 URL 具有 http 或 https 方案时,Netty 路由过滤器会运行。它使用 Netty 的 HttpClient 来发起下游代理请求。响应被放入 ServerWebExchangeUtils.CLIENT_RESPONSE_ATTR 交换属性中,供后续过滤器使用。(还有一个实验性的 WebClientHttpRoutingFilter 执行相同的功能,但不需要 Netty。)
Netty 写响应过滤器
NettyWriteResponseFilter 会在 ServerWebExchangeUtils.CLIENT_RESPONSE_ATTR 交换属性中存在 Netty HttpClientResponse 时运行。它会在所有其他过滤器完成后执行,并将代理响应写回网关客户端响应。(还有一个实验性的 WebClientWriteResponseFilter 执行相同的功能,但不需要 Netty。)
ReactiveLoadBalancerClientFilter
ReactiveLoadBalancerClientFilter 会在名为 ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR 的交换属性中查找 URI。如果该 URL 具有 lb 方案(例如 lb://myservice),它会使用 Spring Cloud ReactorLoadBalancer 将名称(在此示例中为 myservice)解析为实际的主机和端口,并在同一属性中替换该 URI。未修改的原始 URL 会被附加到 ServerWebExchangeUtils.GATEWAY_ORIGINAL_REQUEST_URL_ATTR 属性中的列表中。该过滤器还会检查 ServerWebExchangeUtils.GATEWAY_SCHEME_PREFIX_ATTR 属性,看其是否等于 lb。如果是,则应用相同的规则。以下清单配置了一个 ReactiveLoadBalancerClientFilter:
spring:
cloud:
gateway:
routes:
- id: myRoute
uri: lb://service
predicates:
- Path=/service/**
默认情况下,当 ReactorLoadBalancer 无法找到服务实例时,会返回 503 错误。你可以通过设置 spring.cloud.gateway.loadbalancer.use404=true 来配置网关返回 404 错误。
从 ReactiveLoadBalancerClientFilter 返回的 ServiceInstance 的 isSecure 值会覆盖向 Gateway 发出的请求中指定的方案。例如,如果请求通过 HTTPS 进入 Gateway,但 ServiceInstance 指示其不安全,则下游请求将通过 HTTP 发出。相反的情况也可能适用。但是,如果在 Gateway 配置中为路由指定了 GATEWAY_SCHEME_PREFIX_ATTR,则会剥离前缀,并且路由 URL 生成的方案会覆盖 ServiceInstance 配置。
Gateway 支持所有 LoadBalancer 的功能。你可以在 Spring Cloud Commons 文档 中了解更多相关信息。
RouteToRequestUrl 过滤器
如果 ServerWebExchangeUtils.GATEWAY_ROUTE_ATTR 交换属性中存在 Route 对象,RouteToRequestUrlFilter 就会运行。它会基于请求 URI 创建一个新的 URI,但会使用 Route 对象的 URI 属性进行更新。新的 URI 会被放置在 ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR 交换属性中。
如果URI带有协议前缀,例如 lb:ws://serviceid,lb 协议会从URI中剥离,并放入 ServerWebExchangeUtils.GATEWAY_SCHEME_PREFIX_ATTR 中,以便在过滤器链的后续步骤中使用。
Websocket 路由过滤器
如果 ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR 交换属性中的 URL 具有 ws 或 wss 方案,则 WebSocket 路由过滤器会运行。它使用 Spring WebSocket 基础设施将 WebSocket 请求转发到下游。
您可以通过在URI前添加lb前缀来实现WebSocket的负载均衡,例如lb:ws://serviceid。
如果你使用 SockJS 作为普通 HTTP 的降级方案,你应该同时配置一个普通的 HTTP 路由以及 WebSocket 路由。
以下配置了一个 WebSocket 路由过滤器:
spring:
cloud:
gateway:
routes:
# SockJS route
- id: websocket_sockjs_route
uri: http://localhost:3001
predicates:
- Path=/websocket/info/**
# Normal Websocket route
- id: websocket_route
uri: ws://localhost:3001
predicates:
- Path=/websocket/**
将交换标记为已路由
当网关路由了一个 ServerWebExchange 后,它会通过向交换属性中添加 gatewayAlreadyRouted 来将该交换标记为“已路由”。一旦请求被标记为已路由,其他路由过滤器将不会再次路由该请求,实际上会跳过该过滤器。您可以使用一些便捷方法来将交换标记为已路由,或检查交换是否已被路由。
-
ServerWebExchangeUtils.isAlreadyRouted接收一个ServerWebExchange对象,并检查其是否已被“路由”。 -
ServerWebExchangeUtils.setAlreadyRouted接收一个ServerWebExchange对象,并将其标记为“已路由”。