全局过滤器

GlobalFilter 接口具有与 GatewayFilter 相同的签名。这些是特殊过滤器,有条件地应用于所有路由。

此接口及其用法可能会在未来的里程碑版本中更改。

全局过滤器和 GatewayFilter 的组合排序

当请求匹配到某个路由时,过滤 web 处理器会将 GlobalFilter 的所有实例和路由特定的 GatewayFilter 所有实例添加到过滤器链中。这个组合的过滤器链通过 org.springframework.core.Ordered 接口进行排序,你可以通过实现 getOrder() 方法来设置排序。

Spring Cloud Gateway 在过滤器逻辑执行时区分“前置(pre)”和“后置(post)”阶段(详见工作原理),优先级最高的过滤器在“前置”阶段最先执行,在“后置”阶段最后执行。

以下列表配置了一个过滤器链

ExampleConfiguration.java
@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.metrics.tags.path.enabled 属性(默认为 false),你可以激活带有路径标签的额外指标:

  • path:请求的路径。

然后可以从 `/actuator/metrics/spring.cloud.gateway.requests` 抓取这些指标,并轻松与 Prometheus 集成以创建 Grafana 仪表板。你还可以使用这些有用的指标进行告警,例如参考 告警模板

要启用 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-storeprivate 值)。

它接受两个配置参数:

  • 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:caffeinespring-boot-starter-cache 添加为项目依赖。
如果你的项目创建了自定义的 CacheManager bean,则需要将其标记为 @Primary 或使用 @Qualifier 进行注入。

Forward 路由过滤器

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 具有 httphttps 方案,则 Netty 路由过滤器会运行。它使用 Netty HttpClient 发起下游代理请求。响应被放入 ServerWebExchangeUtils.CLIENT_RESPONSE_ATTR 交换属性中,供后续过滤器使用。(还有一个实验性的 WebClientHttpRoutingFilter 执行相同功能,但不需要 Netty。)

Netty 写入响应过滤器

如果在 ServerWebExchangeUtils.CLIENT_RESPONSE_ATTR 交换属性中存在 Netty HttpClientResponse,则 NettyWriteResponseFilter 会运行。它在所有其他过滤器完成之后运行,并将代理响应写回网关客户端响应。(还有一个实验性的 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

application.yml
spring:
  cloud:
    gateway:
      routes:
      - id: myRoute
        uri: lb://service
        predicates:
        - Path=/service/**
默认情况下,当 ReactorLoadBalancer 找不到服务实例时,会返回 503。你可以通过设置 spring.cloud.gateway.loadbalancer.use404=true 来配置网关返回 404
ReactiveLoadBalancerClientFilter 返回的 ServiceInstanceisSecure 值会覆盖发送到网关的请求中指定的方案(scheme)。例如,如果请求通过 HTTPS 进入网关,但 `ServiceInstance` 表明它不安全,则下游请求会通过 HTTP 发起。反之亦然。但是,如果在网关配置中为路由指定了 GATEWAY_SCHEME_PREFIX_ATTR,则会剥离前缀,并且路由 URL 中产生的方案会覆盖 ServiceInstance 配置。
网关支持所有 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,则会从 URI 中剥离 lb 方案,并将其放置在 ServerWebExchangeUtils.GATEWAY_SCHEME_PREFIX_ATTR 中,供过滤器链后续使用。

Websocket 路由过滤器

如果位于 ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR 交换属性中的 URL 具有 wswss 方案,则 websocket 路由过滤器会运行。它使用 Spring WebSocket 基础设施将 websocket 请求转发到下游。

你可以通过在 URI 前面添加 lb 来对 websocket 进行负载均衡,例如 lb:ws://serviceid

如果你使用 SockJS 作为普通 HTTP 的回退方案,你应该配置正常的 HTTP 路由以及 websocket 路由。

以下列表配置了一个 websocket 路由过滤器

application.yml
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 对象,并将其标记为“已路由”。