Spring Cloud(二十):Gateway 路由匹配表达式工厂,过滤器工厂,全局过滤器,HTTP头过滤器

Spring Cloud Gateway 项目提供了一个基于 Spring 生态体系构建的 API 网关,包括:Spring 5,Spring Boot 2。

Spring Cloud Gateway 旨在提供一种简单而有效的方试将前端请求 URI 路由到后端服务的接口,它还提供了其它的附加实用的功能,例如:安全性,监控/指标,可伸缩性等。

创建 Spring Cloud Gateway 网关服务,需要引入 spring-cloud-starter-gateway 依赖。下面是 Maven 项目中的 pom.xml 添加 Gateway 依赖。

1
2
3
4
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>

如果引入了依赖,但又不想启用,可设置:

1
spring.cloud.gateway.enabled=false

注意事项:

  • Spring Cloud Gateway 基于 Spring Boot 2.x,Spring WebFlux 和 Project Reactor 构建。 因此,当使用 Spring Cloud Gateway 时,许多熟悉的同步库(例如,Spring Data 和 Spring Security)和模式(patterns )可能不适用。 若不熟悉这些项目,建议在使用 Spring Cloud Gateway 之前先阅读它们的文档以熟悉一些新概念。

  • Spring Cloud Gateway 需要 Spring Boot 和 Spring Webflux 提供的 Netty 运行环境。它不是在传递的 Servlet 容器中 或 作为构建成的 WAR 包使用。

    即 Spring Cloud Gateway 与 spring-boot-starter-web(Spring MVC)不兼容,需要移出此 WEB 库,否则服务启动会报异常。

Gateway工作方式

下图从总体上概述了 Spring Cloud Gateway 的工作方式:

Gateway 工作方式

  1. 客户端向 Spring Cloud Gateway 发出请求。

  2. 如果网关处理器映射(Gateway Handler Mapping)确定请求与路由匹配,则将其发送到网关 Web 处理器( Gateway Web Handler)。

  3. 网关 Web 处理器通过特定于请求的过滤器链来执行请求处理。

    过滤器由虚线分隔的原因是,过滤器可以在发送代理请求之前之后运行逻辑。 所有前置过滤器逻辑都会被执行,然后发出代理请求,后端服务接收并处理请求后返回响应,Gateway 将运行后置过滤器逻辑。

从 Gateway 的工作方式可以看出,其核心逻辑是各种类型的过滤器组合成过滤器链,在过滤器链上传递请求并做相应处理,过滤器链是设计模式中的 职责链模式 的经典应用。

注意:若在路由中定义的 URI 没有指定端口,会使用 HTTP 默认的 80 端口,或 HTTPS 默认 443 端口 。

路由与过滤器配置方式

配置匹配(判断)表达式和和过滤器有 2 种方式:分别是 快捷配置完全扩展配置,而大多数使用快捷配置。

名称和属性名称将与代码中的属性名或子属性名匹配,参数通常按快捷方式配置的顺序列出。

快捷配置

快捷配置是通过滤器名来识别,后跟一个等号(**=),然后由逗号分隔的多个参数值(,**)

application.yml

1
2
3
4
5
6
7
8
spring:
cloud:
gateway:
routes:
- id: after_route
uri: https://example.org
predicates:
- Cookie=mycookie,mycookievalue

上面示例定义了 Cookie 路由判断表达式工厂,包含了 2 个参数,Cookie 名是 mycookie ,值将与 mycookievalue 匹配。

完全扩展配置

完全扩展的参数看起来更像带有 键 / 值 (key / value)对的标准 Yaml 配置。 通常会有一个name 键和一个args键(key)。 args键(key)是用于配置判断表达式或过滤器的键值对map(映射)。

application.yml

1
2
3
4
5
6
7
8
9
10
11
spring:
cloud:
gateway:
routes:
- id: after_route
uri: https://example.org
predicates:
- name: Cookie
args:
name: mycookie
regexp: mycookievalue

此示例是上面快捷配置 Cookie 判断表达式的完整配置。

路由判断表达式工厂

Spring Cloud Gateway 将路由匹配作为 Spring WebFlux HandlerMapping 基础架构的一部分。

Spring Cloud Gateway 包括许多内置的路由判断表达式工厂(已自动配置为 Bean)。 所有这些判断表达式都与 HTTP 请求的不同属性匹配。 也可以将多个路由判断表达式工厂按一定的逻辑(logical)和声明(statements)组合使用。

After 时间路由匹配

After路由判断表达式工厂使用参数名为 datetime(Java ZonedDateTime 类型) 来接收日期时间值。此判断表达式将匹配指定日期时间 之后 的请求。示例如下:

application.yml

1
2
3
4
5
6
7
8
spring:
cloud:
gateway:
routes:
- id: after_route
uri: https://example.org
predicates:
- After=2017-01-20T17:42:47.789-07:00[America/Denver]

路由将匹配在 Jan 20, 2017 17:42 Mountain Time (Denver) 日期时间之后的所有请求。

Before 时间路由匹配

Before路由判断表达式工厂使用参数名为 datetime(Java ZonedDateTime 类型) 来接收日期时间值。此判断表达式将匹配指定日期时间 之前 的请求。示例如下:

application.yml

1
2
3
4
5
6
7
8
spring:
cloud:
gateway:
routes:
- id: before_route
uri: https://example.org
predicates:
- Before=2017-01-20T17:42:47.789-07:00[America/Denver]

路由将匹配在 Jan 20, 2017 17:42 Mountain Time (Denver) 日期时间之前的所有请求。

Between 时间路由匹配

Between 路由判断表达式工厂使用 datetime1datetime2 参数(Java ZonedDateTime)接收开始结束日期时间。此判断表达式将匹配在这两个时间范围内的所有请求。datetime2 必须在 datetime1 之后。示例如下:

application.yml

1
2
3
4
5
6
7
8
spring:
cloud:
gateway:
routes:
- id: between_route
uri: https://example.org
predicates:
- Between=2017-01-20T17:42:47.789-07:00[America/Denver], 2017-01-21T17:42:47.789-07:00[America/Denver]

此路由将匹配在 Jan 20, 2017 17:42 Mountain Time (Denver) 之后,Jan 21, 2017 17:42 Mountain Time (Denver) 之前的所有请求。这对要维护某一窗口期非常有用。

Cookie路由判断表达式工厂使用 2 个参数,即 cookie nameregexp(Java 正则表达式),此判断表达式将匹配给定的name且其值与正则表达式匹配的 cookie。示例如下:

application.yml

1
2
3
4
5
6
7
8
spring:
cloud:
gateway:
routes:
- id: cookie_route
uri: https://example.org
predicates:
- Cookie=chocolate, ch.p

此示例将匹配 namechocolate,且值匹配 ch.p 正则表达式的 cookie

Header 路由匹配

Header请求头路由判断表达式工厂使用两个参数: nameregexp(Java 正则表达式),此判断表达式将匹配给定的name且其值与正则表达式匹配的 header。示例如下:

application.yml

1
2
3
4
5
6
7
8
spring:
cloud:
gateway:
routes:
- id: header_route
uri: https://example.org
predicates:
- Header=X-Request-Id, \d+

示例中的路由将匹配持有头名称为 X-Request-Id的请求,且值与 \d+正则表达式匹配(值为一个或多个数字)。

Host 路由匹配

Host主机路由判断表达式工厂使用一个名为 patterns的参数,类型是 list ,值是带有点号( .)作为分隔符的 Ant-style模式。

该判断表达式会匹配与模式匹配的 Host 头。下面示例一个配置 Host 路由的判断表达式:

application.yml

1
2
3
4
5
6
7
8
spring:
cloud:
gateway:
routes:
- id: host_route
uri: https://example.org
predicates:
- Host=**.somehost.org,**.anotherhost.org

此示例路由将匹配持有请求头存在 Host 头,值为 www.somehost.orgbeta.somehost.orgwww.anotherhost.org 的请求。

也支持 URI 模板变量(例如 {sub}.myhost.org),判断表达式将 提取 URI 模板变量(如上例中定义的 sub)作为名称和值(names / values)的映射,并使用 ServerWebExchangeUtils.URI_TEMPLATE_VARIABLES_ATTRIBUTE中定义的键将其放置在ServerWebExchange.getAttributes()中。 这些值可供 GatewayFilter factories 使用。

Method 路由匹配

Method方法路由判断表达式工厂使用名为 methods 的参数,其可以有一个或多个匹配 HTTP 方法的的值。如下示例:

application.yml

1
2
3
4
5
6
7
8
spring:
cloud:
gateway:
routes:
- id: method_route
uri: https://example.org
predicates:
- Method=GET,POST

此示例路由会匹配 GETPOST 请求。

Path 路由匹配

Path路由判断表达式使用两个参数:Spring PathMatcher patterns列表(list)和一个称为matchOptionalTrailingSeparator的可选标志。如下示例:

application.yml

1
2
3
4
5
6
7
8
spring:
cloud:
gateway:
routes:
- id: path_route
uri: https://example.org
predicates:
- Path=/red/{segment},/blue/{segment}

此示例路由匹配请求路径为,例如:*/red/1* 或 /red/blue/blue/gree

该路由判断表达式提取 URI 模板变量(例如,segment)作为 名称 的映射(map),并使用ServerWebExchangeUtils.URI_TEMPLATE_VARIABLES_ATTRIBUTE中定义的键将其放置在ServerWebExchange.getAttributes()中。 这些值可供 GatewayFilter factories 使用。

ServerWebExchange.getAttributes()返回的是一个属性 Map,直接使用 get 方法获取 URI 模板变量。如下示例:

1
2
Map<String, String> uriVariables = ServerWebExchangeUtils.getPathPredicateVariables(exchange);
String segment = uriVariables.get("segment");

Query 路由匹配

Query路由表达式工厂使用两个参数:一个必需的param 和 一个可选的 regexp(Java 正则表达式)。如下示例:

application.yml

1
2
3
4
5
6
7
8
spring:
cloud:
gateway:
routes:
- id: query_route
uri: https://example.org
predicates:
- Query=green

此示例路由会匹配包含有 green查询参数的请求。

application.yml

1
2
3
4
5
6
7
8
spring:
cloud:
gateway:
routes:
- id: query_route
uri: https://example.org
predicates:
- Query=red, gree.

此表达式路由匹配包含 red 查询参数,且值与 gree. 正则表达式匹配的请求。所以 greengreet 都会匹配到。

RemoteAddr 路由匹配

RemoteAddr 远程 IP 地址路由判断表达式使用一个名为 sourcesList 来装值,这些值是 CIDR 表示法(IPv4 或 IPv6)字符串。例如 192.168.0.1/16(其中 192.168.0.1 是 IP 地址,16 是子网掩码)。如下示例:

application.yml

1
2
3
4
5
6
7
8
spring:
cloud:
gateway:
routes:
- id: remoteaddr_route
uri: https://example.org
predicates:
- RemoteAddr=192.168.1.1/24

路由将匹配请求的源地址,例如,192.168.1.10。

修改远程地址解析方式

默认,RemoteAddr 路由判断表达式工厂使用请求中携带的远程地址,如果 Spring Cloud Gateway 部署在一个代理层的后面,则这种方式可能无法匹配到真实的客户端 IP 地址。

可以通过设置自定义的 RemoteAddressResolver来自定义解析远程地址的方式。SpringCloudGateway 提供了一个非默认的远程地址解析器,它基于 X-Forwarded-For头 和 xForwardedRemoteAddResolver

XForwardedRemoteAddressResolver 有两个静态构造方法,分别采用不同的安全方式:

  • XForwardedRemoteAddressResolver::trustAll返回一个 RemoteAddressResolver,它总是使用在 X-Forwarded-For头中发现的第一个 IP 地址。此方法易受欺骗,因为恶意客户端可能为 X-Forwarded-for 设置初始值,解析器将接受该值。

  • XForwardedRemoteAddressResolver::maxTrustedIndex获取一个索引,该索引与在 Spring Cloud Gateway 前面运行的受信任基础结构的数量相关。

    例如,如果 Spring Cloud Gateway 只能通过 HAProxy 访问,则应使用值 1。如果在访问 Spring Cloud Gateway 之前需要两跳可信基础设施,则应使用值 2。

    考虑下面的头值:

    1
    X-Forwarded-For: 0.0.0.1, 0.0.0.2, 0.0.0.3

    maxTrustedIndex值将使用对应的远程地址:

    maxTrustedIndex result
    [Integer.MIN_VALUE,0] (invalid, IllegalArgumentException during initialization)
    1 0.0.0.3
    2 0.0.0.2
    3 0.0.0.1
    [4, Integer.MAX_VALUE] 0.0.0.1

    以下示例显示了如何使用 Java 实现相同的配置:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    RemoteAddressResolver resolver = XForwardedRemoteAddressResolver.maxTrustedIndex(1);
    ...
    .route("direct-route",
    r -> r.remoteAddr("10.1.1.1", "10.10.1.1/24")
    .uri("https://downstream1")
    .route("proxied-route",
    r -> r.remoteAddr(resolver, "10.10.1.1", "10.10.1.1/24")
    .uri("https://downstream2")
    )

Weight 路由匹配

Weight 权重路由使用两个参数:groupweight(int 型),每组会计算权重。如下示例:

1
2
3
4
5
6
7
8
9
10
11
12
spring:
cloud:
gateway:
routes:
- id: weight_high
uri: https://weighthigh.org
predicates:
- Weight=group1, 8
- id: weight_low
uri: https://weightlow.org
predicates:
- Weight=group1, 2

此示例路由会将 80% 的流量转发到 weighthigh.org,20% 的流量转发到 weightlow.org。网关的 权重路由

GatewayFilter 工厂

路由过滤器允许以某种方式修改传入的 HTTP请求 或传出的 HTTP响应。 路由过滤器的作用域是特定路由,Spring Cloud Gateway 提供了许多内置的 GatewayFilter Factories(网关过滤器工厂)。

备注:更多关于如何使用下面系列过滤器的详细示例,可参考单元测试(unit tests)。

AddRequestHeader

AddRequestHeader 添加请求头 GatewayFilter工厂使用 namevalue 参数。如下示例:

application.yml

1
2
3
4
5
6
7
8
spring:
cloud:
gateway:
routes:
- id: add_request_header_route
uri: https://example.org
filters:
- AddRequestHeader=X-Request-red, blue

此示例将 X-Request-red:blue头添加到所有匹配要转发到下游服务的请求头中。

AddRequestHeader 知道用于匹配路径(path)或主机(host)的 URI 变量。 URI 变量可以在值中使用,并在运行时扩展。 如下示例:

application.yml

1
2
3
4
5
6
7
8
9
10
spring:
cloud:
gateway:
routes:
- id: add_request_header_route
uri: https://example.org
predicates:
- Path=/red/{segment}
filters:
- AddRequestHeader=X-Request-Red, Blue-{segment}

AddRequestParameter

AddRequestParameter添加请求参数GatewayFilter工厂使用 namevalue 参数。如下示例:

application.yml

1
2
3
4
5
6
7
8
spring:
cloud:
gateway:
routes:
- id: add_request_parameter_route
uri: https://example.org
filters:
- AddRequestParameter=red, blue

示例将为所有匹配转发给下游的请求的查询字符串(request’s query string)添加red=blue

AddRequestParameter 知道用于匹配路径(path)或主机(host)的 URI 变量。 URI 变量可以在值中使用,并在运行时扩展。 如下示例:

application.yml

1
2
3
4
5
6
7
8
9
10
spring:
cloud:
gateway:
routes:
- id: add_request_parameter_route
uri: https://example.org
predicates:
- Host: {segment}.myhost.org
filters:
- AddRequestParameter=foo, bar-{segment}

AddResponseHeader

AddResponseHeader 添加响应头GatewayFilter工厂使用 namevalue 参数。如下示例:

application.yml

1
2
3
4
5
6
7
8
spring:
cloud:
gateway:
routes:
- id: add_response_header_route
uri: https://example.org
filters:
- AddResponseHeader=X-Response-Red, Blue

此示例将 X-Response-Foo:Bar头添加到所有匹配请求的下游响应头中。

AddResponseHeader 知道用于匹配路径(path)或主机(host)的 URI 变量。 URI 变量可以在值(value)中使用,并在运行时扩展。 如下示例:

application.yml

1
2
3
4
5
6
7
8
9
10
spring:
cloud:
gateway:
routes:
- id: add_response_header_route
uri: https://example.org
predicates:
- Host: {segment}.myhost.org
filters:
- AddResponseHeader=foo, bar-{segment}

DedupeResponseHeader

DedupeResponseHeader移除重复的响应头 GatewayFilter 工厂使用一个 name参数和一个可选的strategy参数,name可以包含以空隔为分隔符的头名称列表。如下示例:

application.yml

1
2
3
4
5
6
7
8
spring:
cloud:
gateway:
routes:
- id: dedupe_response_header_route
uri: https://example.org
filters:
- DedupeResponseHeader=Access-Control-Allow-Credentials Access-Control-Allow-Origin

此示例将删除 Access-Control-Allow-CredentialsAccess-Control-Allow-Origin 响应头中的重复值,如果在网关 CORS 逻辑和下游服务逻辑都添加它们情况下。

DedupeResponseHeader过滤器也能接收一个可选参数strategy,它接受的值有 RETAIN_FIRST (default), RETAIN_LAST, 和RETAIN_UNIQUE

Hystrix

注意:Netflix 将 Hystrix 置于维护模式。建议使用带有 Resilience4JSpring Cloud CircuitBreaker Gateway Filter,因为 Hystrix 的支持将在未来的版本中删除。

Hystrix 是 Netflix 实现 circuit breaker pattern (熔断器模式)的一个库。Hystrix GatewayFilter 允许将熔断器引入网关路由,保护的服务不受级联故障的影响,并允许在下游故障时提供回退响应。

要在项目中启用 Hystrix GatewayFilter 实例,需要添加来自 Spring Cloud Netflix 的依赖spring-cloud-starter-netflix-hystrix

Hystrix GatewayFilter 工厂需要一个 name 参数,即 HystrixCommand 的名称。示例如下:

application.yml

1
2
3
4
5
6
7
8
spring:
cloud:
gateway:
routes:
- id: hystrix_route
uri: https://example.org
filters:
- Hystrix=myCommandName

此示例将其余过滤器包装在命令名称为 myCommandNameHystrixCommand 中。

Hystrix 过滤器还可以接受可选参数 fallbackUri 。目前,只支持 forward:方式,如果回调被调用,请求会被转发到匹配 URI 的 Controller。示例如下:

application.yml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
spring:
cloud:
gateway:
routes:
- id: hystrix_route
uri: lb://backing-service:8088
predicates:
- Path=/consumingserviceendpoint
filters:
- name: Hystrix
args:
name: fallbackcmd
fallbackUri: forward:/incaseoffailureusethis
- RewritePath=/consumingserviceendpoint, /backingserviceendpoint

Hystrix 回调被调用时,将转发到/incaseoffailureusethis URI。注意,这个示例还演示了(可选的)Spring Cloud Netflix Ribbon load-balancing(在目标URI上定义了 lb 前缀)。

主要场景是将fallbackUri用于网关应用程序中的内部控制器或处理程序。但是,也可以将请求重新路由到外部应用程序中的控制器或处理程序。如下所示:

application.yml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
spring:
cloud:
gateway:
routes:
- id: ingredients
uri: lb://ingredients
predicates:
- Path=//ingredients/**
filters:
- name: Hystrix
args:
name: fetchIngredients
fallbackUri: forward:/fallback
- id: ingredients-fallback
uri: http://localhost:9994
predicates:
- Path=/fallback

在此示例中,网关应用程序中没有fallback端点或处理程序。但是,在另一个应用程序中有一个是在 localhost:9994 的回调端点。

在请求被转发到回退(fallback)的情况下,Hystrix 网关过滤器还提供导致该请求的Throwable。它作为ServerWebExchangeUtils.HYSTRIX_EXECUTION_EXCEPTION_ATTR属性添加到ServerWebExchange中,在处理网关应用程序中的回退时可以使用该属性。

或者在外部控制器 / 处理程序场景中,可以添加带有异常详细信息的头。更多信息可参考 FallbackHeaders GatewayFilter Factory section.

可以使用全局默认值配置 Hystrix 设置(如 超时),也可以使用应用程序属性逐个路由配置 Hystrix 设置,如 Hystrix wiki 上所述。

为上面的示例设置 5 秒的路由超时,可以使用如下配置:

1
hystrix.command.fallbackcmd.execution.isolation.thread.timeoutInMilliseconds: 5000

Spring Cloud CircuitBreaker

Spring Cloud CircuitBreaker GatewayFilter 工厂使用 Spring Cloud CircuitBreaker APIs 将 Gateway 路由包装在熔断器中(circuit breaker)。

Spring Cloud CircuitBreaker 支持可与 Spring Cloud Gateway 一起使用的两个库 HystrixResilience4J。 由于Netflix 已将 Hystrix 置于仅维护模式,因此建议使用 Resilience4J

要启用 Spring Cloud CircuitBreaker,需要引入 spring-cloud-starter-circuitbreaker-reactor-resilience4jspring-cloud-starter-netflix-hystrix 依赖。配置如下示例:

application.yml

1
2
3
4
5
6
7
8
spring:
cloud:
gateway:
routes:
- id: circuitbreaker_route
uri: https://example.org
filters:
- CircuitBreaker=myCircuitBreaker

要配置断路器,请参阅所使用的基础断路器实现的配置。

Spring Cloud CircuitBreaker 过滤器也可以接收可选参数 fallbackUri 参数。目前,只支持 forward: 方式的 URI。如果执行了回退,请求会被转发到匹配 URI 的控制器(Controller)。如下示例回退转发:

application.yml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
spring:
cloud:
gateway:
routes:
- id: circuitbreaker_route
uri: lb://backing-service:8088
predicates:
- Path=/consumingServiceEndpoint
filters:
- name: CircuitBreaker
args:
name: myCircuitBreaker
fallbackUri: forward:/inCaseOfFailureUseThis
- RewritePath=/consumingServiceEndpoint, /backingServiceEndpoint

上面示例的 Java 实现:

1
2
3
4
5
6
7
8
@Bean
public RouteLocator routes(RouteLocatorBuilder builder) {
return builder.routes()
.route("circuitbreaker_route", r -> r.path("/consumingServiceEndpoint")
.filters(f -> f.circuitBreaker(c -> c.name("myCircuitBreaker").fallbackUri("forward:/inCaseOfFailureUseThis"))
.rewritePath("/consumingServiceEndpoint", "/backingServiceEndpoint")).uri("lb://backing-service:8088")
.build();
}

上面示例:当熔断器回退被调用时,将转发请求到 /inCaseOfFailureUseThis URI。 请注意,此示例还演示了(可选)Spring Cloud Netflix Ribbon load-balancing(负载平衡)(由目标 URI 上的 lb 前缀定义)。

主要场景是使用 fallbackUri 在网关应用程序内定义内部控制器或处理程序。 但是,还可以将请求重新路由到外部应用程序中的控制器或处理程序,如下所示:

application.yml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
spring:
cloud:
gateway:
routes:
- id: ingredients
uri: lb://ingredients
predicates:
- Path=//ingredients/**
filters:
- name: CircuitBreaker
args:
name: fetchIngredients
fallbackUri: forward:/fallback
- id: ingredients-fallback
uri: http://localhost:9994
predicates:
- Path=/fallback

此示例,网关应用没有 fallback 端点,但在另一个注册 localhost:9994 的应用有回退端点。

如果出现了请求被转发到回退(回调),则 Spring Cloud CircuitBreaker Gateway 过滤器还会提供引发该请求的Throwable。 它作为 ServerWebExchangeUtils.CIRCUITBREAKER_EXECUTION_EXCEPTION_ATTR 属性添加到ServerWebExchange,可在处理网关应用程序中的回退时使用。

对于外部的控制器/处理器(controller/handler)场景,可以添加带有异常详细信息的头。见下面章节。

FallbackHeaders

FallbackHeaders 工厂允许在转发到外部应用程序中的 fallbackUri的请求头中添加 HystrixSpring Cloud CircuitBreaker执行异常详细信息。如下所示:

application.yml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
spring:
cloud:
gateway:
routes:
- id: ingredients
uri: lb://ingredients
predicates:
- Path=//ingredients/**
filters:
- name: CircuitBreaker
args:
name: fetchIngredients
fallbackUri: forward:/fallback
- id: ingredients-fallback
uri: http://localhost:9994
predicates:
- Path=/fallback
filters:
- name: FallbackHeaders
args:
executionExceptionTypeHeaderName: Test-Header

在此示例中,在运行断路器时发生执行异常之后,该请求将转发到在 localhost:9994上运行的应用程序中的fallback端点或处理程序。带有异常类型、消息和(如果可用)根原因异常类型的头数据将由 FallbackHeaders 过滤器添加到请求中。

FallbackHeadersGatewayFilterFactory 有个静态内部类 Config,可以通过设置以下参数的值来重写配置中的头的名称,括号中是默认值。

  • executionExceptionTypeHeaderName (Execution-Exception-Type)
  • executionExceptionMessageHeaderName (Execution-Exception-Message)
  • rootCauseExceptionTypeHeaderName (Root-Cause-Exception-Type)
  • rootCauseExceptionMessageHeaderName (Root-Cause-Exception-Message)

MapRequestHeader

MapRequestHeader 请求头映射,使用 fromHeadertoHeader 参数接收。它创建一个新命名的头(toHeader),并从传入的 HTTP 请求的现有命名头(fromHeader) 中提取值。

如果输入的 不存在,则过滤器不起作用;如果新命名的头已存在,则它的值将使用新值进行扩展。如下示例:

application.yml

1
2
3
4
5
6
7
8
spring:
cloud:
gateway:
routes:
- id: map_request_header_route
uri: https://example.org
filters:
- MapRequestHeader=Blue, X-Request-Red

X-Request-Red:<values>头添加到转发给下游服务的请求中,其值来自传入的 HTTP请求的 Blue头的值。

PrefixPath

PrefixPath增加路径前缀,使用单个 prefix 参数接收。示例如下:

application.yml

1
2
3
4
5
6
7
8
spring:
cloud:
gateway:
routes:
- id: prefixpath_route
uri: https://example.org
filters:
- PrefixPath=/mypath

示例是给所有匹配请求的路径加上/mypath 前缀。一个 /hello 的请求会被发送到 /mypath/hello

PreserveHostHeader

PreserveHostHeader GatewayFilter factory 没有参数。此过滤器设置一个路由过滤器检查的请求属性,以确定是否发送请求头中的主机Host信息,而不是由 HTTP 客户端确定的主机头。

application.yml

1
2
3
4
5
6
7
8
spring:
cloud:
gateway:
routes:
- id: preserve_host_route
uri: https://example.org
filters:
- PreserveHostHeader

设置了 PreserveHostHeader过滤器,过滤器会把 ServerWebExchangeUtils.PRESERVE_HOST_HEADER_ATTRIBUTE = true保存到 ServerWebExchange的属性中(attributes:是个 Map 结构)。在 NettyRoutingFilter 过滤器中,会取出该属性,判断值为 true,就取出原始请求头中的 Host 添加进新的请求(request)中。

RequestRateLimiter

RequestRateLimiter请求限流,使用RateLimiter的实现来决定当前请求是否允许被处理,如果否,返回HTTP 429 - Too Many Requests

过滤器会使用一个可选参数 keyResolver 和 指定的限流参数。keyResolver是一个实现 keyResolver 接口的 Bean,在配置中,通过 name 使用 SpEL来引用 Bean。例如,#{@myKeyResolver} 是一个 SpEL 表达式,引用 name 为 myKeyResolver 的 Bean。下面是 KeyResolver 接口:

KeyResolver.java

1
2
3
public interface KeyResolver {
Mono<String> resolve(ServerWebExchange exchange);
}

KeyResolver 接口允许可插拔策略派生用于限制请求的密钥。 在未来的里程碑版本中,将有一些 KeyResolver 实现。

KeyResolver 的默认实现是 PrincipalNameKeyResolver,它会从 ServerWebExchange检索 Principal并调用 Principal.getName()

默认情况下,如果 KeyResolver 找不到 Key,请求就会被拒绝。也可以通过设置来调整此行为:

1
2
spring.cloud.gateway.filter.request-rate-limiter.deny-empty-key=true|flase
spring.cloud.gateway.filter.request-rate-limiter.empty-key-status-code=

RequestRateLimiterGatewayFilterFactory.java

1
2
3
4
5
6
7
/**
* Switch to deny requests if the Key Resolver returns an empty key, defaults to true.
*/
private boolean denyEmptyKey = true;

/** HttpStatus to return when denyEmptyKey is true, defaults to FORBIDDEN. */
private String emptyKeyStatusCode = HttpStatus.FORBIDDEN.name();

注意:RequestRateLimiter 不支持快捷方式的配置。下面示例的配置是无效的:

application.properties

1
2
# INVALID SHORTCUT CONFIGURATION
spring.cloud.gateway.routes[0].filters[0]=RequestRateLimiter=2, 2, #{@userkeyresolver}

Redis RateLimiter 限流

Redis RateLimiter 的实现是基于在 Stripe 完成的工作。它需要引入 spring-boot-starter-data-redis-reactive Spring Boot starter 包。

算法使用的是令牌桶算法(Token Bucket Algorithm

  • redis-rate-limiter.replenishRate 属性:允许每秒可以处理的请求数,没有任何丢弃的请求。该值是令牌桶的流入速率。
  • redis-rate-limiter.burstCapacity 属性:允许在一秒内执行的最大请求数。该值是令牌桶持有的令牌数。设置值为 0 将阻止所有请求。
  • redis-rate-limiter.requestedTokens 属性:一个请求需要消费的令牌数。这是每个请求从 bucket 中获取的令牌数,默认为 1。

通过设置 replenishRateburstCapacity 相同的值可以实现固定的速率。通过将burstCapacity设置为高于 replenishRate,可以允许临时突发请求流量。

注意:两次突发流量应间隔一段时间,以便于令牌桶中有多余的令牌供突发请求使用,若是连续的突发流量,令牌耗尽则会丢弃请求(返回 HTTP 429 - Too Many Request)。下面列了 redis-rate-limiter 的配置。

application.yml

1
2
3
4
5
6
7
8
9
10
11
12
spring:
cloud:
gateway:
routes:
- id: requestratelimiter_route
uri: https://example.org
filters:
- name: RequestRateLimiter
args:
redis-rate-limiter.replenishRate: 10
redis-rate-limiter.burstCapacity: 20
redis-rate-limiter.requestedTokens: 1

配置示例:令牌产生速度是每秒 10 个,桶中可保存 20 个令牌(能处理的突发请求数,下一秒则只能处理 10 个请求),每个请求消耗 1 个令牌。

如果设置 replenishRate=1,requestedTokens=60,burstCapacity=60,将导致每分钟只能处理 1 个请求(1 request/min)。因为一个请求消耗 60 个令牌,生成 60 个令牌需要 1 分钟。

KeyResolver 的 Java 配置:

1
2
3
4
5
@Bean
KeyResolver userKeyResolver() {
//一个获取请求参数 user 的简单方法
return exchange -> Mono.just(exchange.getRequest().getQueryParams().getFirst("user"));
}

也可以定义一个实现 RateLimiter接口的限流器,并注册为 Bean。配置中,可引用使用了 SpEL 的 Bean 名。#{@RateLimiter} 是一个 SpEL 表达式,引用名为 myRateLimiter 的 Bean。

下面配置定义了一个使用上面定义的 keyrolver 的速率限流器:

application.yml

1
2
3
4
5
6
7
8
9
10
11
spring:
cloud:
gateway:
routes:
- id: requestratelimiter_route
uri: https://example.org
filters:
- name: RequestRateLimiter
args:
rate-limiter: "#{@myRateLimiter}"
key-resolver: "#{@userKeyResolver}"

RedirectTo

RedirectTo 重定向到,使用 2 个参数:statusurl

  • status: HTTP 的 300 系统的重定向编码,例如 301。
  • url:一个有效的 URL,即是 Location 头的值。

对于相对重定向,路由定义的 URI 应使用 uri: no://op

下面配置示例:

application.yml

1
2
3
4
5
6
7
8
spring:
cloud:
gateway:
routes:
- id: prefixpath_route
uri: https://example.org
filters:
- RedirectTo=302, https://acme.org

这将发送一个状态码为 302,Location:https://acme.org 头(header)以执行重定向。

RemoveRequestHeader

RemoveRequestHeader 移除请求头,使用一个 name 参数,以指标要移除的头名称。如下示例:

application.yml

1
2
3
4
5
6
7
8
spring:
cloud:
gateway:
routes:
- id: removerequestheader_route
uri: https://example.org
filters:
- RemoveRequestHeader=X-Request-Foo

示例在转发请求到下游服务之前移除 X-Request-Foo 请求头。

RemoveResponseHeader

RemoveResponseHeader 移除响应头,使用 name 参数,以指示要移除的头名称。示例如下:

application.yml

1
2
3
4
5
6
7
8
spring:
cloud:
gateway:
routes:
- id: removeresponseheader_route
uri: https://example.org
filters:
- RemoveResponseHeader=X-Response-Foo

示例是在将响应发送到网关客户端之前,从响应中移除 X-Response-Foo头。

若要移除任何类型的敏感头,应该为任何路由配置此过滤器。此外,还可以使用spring.cloud.gateway.default-filters 配置此过滤器,并将其应用于所有路由。

RemoveRequestParameter

RemoveRequestParameter 移除请求参数,使用 name 参数,以指示要移除的查询参数。示例如下:

application.yml

1
2
3
4
5
6
7
8
spring:
cloud:
gateway:
routes:
- id: removerequestparameter_route
uri: https://example.org
filters:
- RemoveRequestParameter=red

示例,在转发请求到下游服务之前移除请求中的 red 参数。

RewritePath

RewritePath 重写路径,使用 regexpreplacement参数。这里使用 Java 的正则表达式提供一种灵活的方式来重写请求路径。如下示例:

application.yml

1
2
3
4
5
6
7
8
9
10
spring:
cloud:
gateway:
routes:
- id: rewritepath_route
uri: https://example.org
predicates:
- Path=/foo/**
filters:
- RewritePath=/red(?<segment>/?.*), $\{segment}

示例,对于 /red/blue 请求路径,在发送请求到下游服务之前将重写路径为 /blue注意: $ 符应使用 $\,因为这是 YAML 特定的。

RewriteLocationResponseHeader

RewriteLocationResponseHeader 重写响应头中 Location 的值,通常是为了摆脱后端特定的细节,使用 stripVersionMode, locationHeaderName, hostValueprotocolsRegex 参数来接收值。如下示例:

application.yml

1
2
3
4
5
6
7
8
spring:
cloud:
gateway:
routes:
- id: rewritelocationresponseheader_route
uri: http://example.org
filters:
- RewriteLocationResponseHeader=AS_IN_REQUEST, Location, ,

例如,一个 POST api.example.com/some/object/name请求,其响应头 Location 的值是 object-service.prod.example.net/v2/some/object/id 会被重写为 api.example.com/some/object/id

  • stripVersionMode 参数:可能有以下的值:NEVER_STRIP, AS_IN_REQUEST (默认),和 ALWAYS_STRIP

    • NEVER_STRIP:不剥离版本号(version),即使原始请求路径不包含版本号。
    • AS_IN_REQUEST:仅当原始请求路径不包含版本号时,才剥离该版本号。
    • ALWAYS_STRIP:始终剥离版本号,即使原始请求路径包含版本号。
  • hostValue 参数:(如果提供)用于替换响应 Location 头的 host:port 部分。 如果未提供,则使用请求 Host头的值。

  • protocolsRegex 参数:必须是一个有效的正则表达式字符串(String),用于匹配协议名称。如果不匹配,则过滤器不执行任何操作。默认为 http | https | ftp | ftps

RewriteResponseHeader

RewriteResponseHeader重写响应头,使用 name, regexpreplacement 参数接收值。使用 Java 正则表达式提供一种灵活的方式来重写响应头中的值。示例如下:

application.yml

1
2
3
4
5
6
7
8
spring:
cloud:
gateway:
routes:
- id: rewriteresponseheader_route
uri: https://example.org
filters:
- RewriteResponseHeader=X-Response-Red, , password=[^&]+, password=***

示例中,一个头的值为 /42?user=ford&password=omg!what&flag=true,在发出下游请求后,将此头设置为 /42?user=ford&password=***&flag=true。注意使用 $\ 代表 $,这是 YAML 格式指定的。

SaveSession

SaveSession 保存 Session,在向下游服务转发请求之前强制执行 WebSession::save操作

当使用一些类似于 Spring Session 的数据与惰性数据(lazy data)存储一起使用时,这特别有用,需要确保在进行转发请求之前已保存会话状态。示例如下:

application.yml

1
2
3
4
5
6
7
8
9
10
spring:
cloud:
gateway:
routes:
- id: save_session
uri: https://example.org
predicates:
- Path=/foo/**
filters:
- SaveSession

如果将 Spring Security 与 Spring Session 集成,并希望确保安全性详细信息已转发到远程进程,那么这一点至关重要。

SecureHeaders

SecureHeaders会向响应添加多个头数据,主要是根据这篇博客的建议:Everything you need to know about HTTP security headers

会添加下面这些头,括号中是默认值。

  • X-Xss-Protection:1 (mode=block)
  • Strict-Transport-Security (max-age=631138519)
  • X-Frame-Options (DENY)
  • `X-Content-Type-Options (nosniff)
  • Referrer-Policy (no-referrer)
  • Content-Security-Policy (default-src ‘self’ https:; font-src ‘self’ https: data:; img-src ‘self’ https: data:; object-src ‘none’; script-src https:; style-src ‘self’ https: ‘unsafe-inline’)
  • X-Download-Options (noopen)
  • X-Permitted-Cross-Domain-Policies (none)

若要改变这些默认值,在 spring.cloud.gateway.filter.secure-headers命名空间中设置适当的值。下面这些属性可设置:

  • xss-protection-header
  • strict-transport-security
  • x-frame-options
  • x-content-type-options
  • referrer-policy
  • content-security-policy
  • x-download-options
  • x-permitted-cross-domain-policies

这些属性是与上面列出要添加的头是对应的,在 SecureHeadersProperties.java 安全头属性类文件中可以看到。

要禁用默认值,设置spring.cloud.gateway.filter.secure-headers.disable属性,使用逗号分隔符(,)。注意,值必须是安全标头(secure headers)的小写全名。如下所示:

1
spring.cloud.gateway.filter.secure-headers.disable=x-frame-options,strict-transport-security

SetPath

SetPath设置路径,使用一个路径template 参数接收。它提供了一种简单的方法,通过允许路径的模板片段来操作请求路径。这使用了 Spring 框架中的 URI 模板,允许多个匹配片段。如下示例:

application.yml

1
2
3
4
5
6
7
8
9
10
spring:
cloud:
gateway:
routes:
- id: setpath_route
uri: https://example.org
predicates:
- Path=/red/{segment}
filters:
- SetPath=/{segment}

此示例,对于 /red/blue 的请求路径,在发给下游服务之前将路径设置为 /blue

SetRequestHeader

SetRequestHeader重置请求头的值,使用 name value 参数接收值。如下所示:

1
2
3
4
5
6
7
8
spring:
cloud:
gateway:
routes:
- id: setrequestheader_route
uri: https://example.org
filters:
- SetRequestHeader=X-Request-Red, Blue

GatewayFilter 给指定名称的请求头(name)替换(而不是添加)其值。示例中,如果下游服务器响应X-Request-Red:1234,则将其值替换为X-Request-Red:Blue,这是其它下游服务将收到的内容。

SetRequestHeader 知道用于匹配路径(path)或主机(host)的 URI变量URI变量可以在要值中使用,并在运行时展开。如下示例:

application.yml.

1
2
3
4
5
6
7
8
9
10
spring:
cloud:
gateway:
routes:
- id: setrequestheader_route
uri: https://example.org
predicates:
- Host: {segment}.myhost.org
filters:
- SetRequestHeader=foo, bar-{segment}

SetResponseHeader

SetResponseHeader重置响应头中的值,使用 namevalue参数接收值。如下示例:

application.yml

1
2
3
4
5
6
7
8
spring:
cloud:
gateway:
routes:
- id: setresponseheader_route
uri: https://example.org
filters:
- SetResponseHeader=X-Response-Red, Blue

GatewayFilter 会替换所有指定请求头名称的值(而不是添加)。示例,如果下游服务响应头是X-Response-Red:1234,Gateway 客户端会收到被替为 X-Response-Red:Blue的响应头。

SetResponseHeader知道用于匹配路径(path)和主机(host)的 URI变量,变量可以在值中使用,并在运行时展开。示例如下:

1
2
3
4
5
6
7
8
9
10
spring:
cloud:
gateway:
routes:
- id: setresponseheader_route
uri: https://example.org
predicates:
- Host: {segment}.myhost.org
filters:
- SetResponseHeader=foo, bar-{segment}

SetStatus

SetStatus 设置响应头的 HTTP 编码,使用单个参数 status 接收。值必须是一个有效的 HttpStatus,它可能是个整数 404 或 枚举字符串形式表示的:NOT_FOUND。如下示例:

application.yml

1
2
3
4
5
6
7
8
9
10
11
12
spring:
cloud:
gateway:
routes:
- id: setstatusstring_route
uri: https://example.org
filters:
- SetStatus=BAD_REQUEST
- id: setstatusint_route
uri: https://example.org
filters:
- SetStatus=401

此示例,设置响应的 HTTP status 为 401。

可以配置 SetStatus GatewayFilter,以在响应的头中从代理请求返回原始 HTTP 状态代码。如果配置了以下属性,则会将头添加到响应中:

application.yml

1
2
3
4
5
spring:
cloud:
gateway:
set-status:
original-status-header-name: original-http-status

StripPrefix

StripPrefix 剥离前缀片段,使用一个参数 parts 接收。parts 参数声明路径(path)中有几部分要从请求中剥离,在发送到下游服务之前。如下示例:

application.yml

1
2
3
4
5
6
7
8
9
10
spring:
cloud:
gateway:
routes:
- id: nameRoot
uri: https://nameservice
predicates:
- Path=/name/**
filters:
- StripPrefix=2

此示例,当一个请求通过网关访问 /name/blue/red,对 nameservice 的请求看起来像 nameservice/red,剥离了前缀 2 部分。

Retry

Retry重试,支持下面这些参数:

  • retries:重试次数

  • status:重试的 HTTP 状态码,使用 org.springframework.http.HttpStatus

  • method:重试使用的 HTTP 请求方式,使用 org.springframework.http.HttpMethod

  • series:重试的一系列状态码,使用 org.springframework.http.HttpStatus.Series

  • exceptions:那些异常需要重试。

  • backoff:为重试配置的间隔指数。重试在 firstBackoff *(factor ^ n)的间隔后执行,其中 n 是重试次数,是累加的。

    如果配置了 maxBackoff,则将应用的最大重试间隔限制为 maxBackoff。如果 basedOnPreviousValuetrue,则使用prevBackoff * factor计算回退量。

    示例,如果第 1 次重试是间隔 2 秒,则第 2 次重试与第 1 次重试间隔 4 秒,第 3 次重试与 第 2 次重试间隔 8 秒。

如果启用 Retry 过滤器,下面是此过滤器的默认值:

  • retries:3 次
  • series:5XX 系列
  • methods:GET 方式
  • exceptions:IOException 和 TimeoutException
  • backoff:禁用

以下是 Retry GatewayFilter 配置示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
spring:
cloud:
gateway:
routes:
- id: retry_test
uri: http://localhost:8080/flakey
predicates:
- Host=*.retry.com
filters:
- name: Retry
args:
retries: 3
statuses: BAD_GATEWAY
methods: GET,POST
backoff:
firstBackoff: 10ms
maxBackoff: 50ms
factor: 2
basedOnPreviousValue: false

注意:当将重试过滤器与带有forward:前缀的 URL 一起使用时,应仔细编写目标端点,以便在发生错误的情况下,它不会做任何可能导致响应发送到客户端并提交的操作。 例如,如果目标端点是带注释的控制器,则目标控制器方法不应返回带有错误状态代码的 ResponseEntity。 相反,它应该引发 Exception发出错误信号(例如,通过Mono.error(ex)返回值),可以配置重试过滤器来进行重试处理。

警告:当将重试过滤器与任何带有 body 的 HTTP方法一起使用时,body 将被缓存,并且网关将受到内存的限制。 body 将缓存在 ServerWebExchangeUtils.CACHED_REQUEST_BODY_ATTR定义的请求属性中,对象的类型是org.springframework.core.io.buffer.DataBuffer

RequestSize

当请求大小大于限制时,RequestSize 网关过滤器工厂可以限制请求到达下游服务。

过滤器使用maxSize参数。maxSize 是一个 DataSize类型,因此值(value)可以定义为数字,后跟可选的DataUnit 后缀,例如 KBMB。默认是 B代表字节。它是请求的允许大小限制,以字节为单位。配置如下所示:

application.yml

1
2
3
4
5
6
7
8
9
10
11
12
spring:
cloud:
gateway:
routes:
- id: request_size_route
uri: http://localhost:8080/upload
predicates:
- Path=/upload
filters:
- name: RequestSize
args:
maxSize: 5000000

当请求因大小而被拒绝时,RequestSize GatewayFilter 工厂将响应状态设置为 413 Payload Too Large,并带有一个附加报头 errorMessage。 以下示例这样的 errorMessage:

1
errorMessage` : `Request size is larger than permissible limit. Request size is 6.0 MB where permissible limit is 5.0 MB

注意:如果未在路由定义中作为筛选器参数提供,则默认请求大小设置为 5 MB

ModifyRequestBody

ModifyRequestBody修改请求体,在请求被网关发给下游服务之前。只能使用 Java DSL 来配置此过滤器。如下示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
@Bean
public RouteLocator routes(RouteLocatorBuilder builder) {
return builder.routes()
.route("rewrite_request_obj", r -> r.host("*.rewriterequestobj.org")
.filters(f -> f.prefixPath("/httpbin")
.modifyRequestBody(String.class, Hello.class, MediaType.APPLICATION_JSON_VALUE,
(exchange, s) -> return Mono.just(new Hello(s.toUpperCase())))).uri(uri))
.build();
}

static class Hello {
String message;

public Hello() { }

public Hello(String message) {
this.message = message;
}

public String getMessage() {
return message;
}

public void setMessage(String message) {
this.message = message;
}
}

ModifyResponseBody

ModifyResponseBody修改响应体,在返回响应给客户端之前。只能使用 Java DSL 来配置此过滤器。如下示例:

1
2
3
4
5
6
7
8
9
@Bean
public RouteLocator routes(RouteLocatorBuilder builder) {
return builder.routes()
.route("rewrite_response_upper", r -> r.host("*.rewriteresponseupper.org")
.filters(f -> f.prefixPath("/httpbin")
.modifyResponseBody(String.class, String.class,
(exchange, s) -> Mono.just(s.toUpperCase()))).uri(uri)
.build();
}

defaultFilters

添加一个过滤器来应用于所有的路由,可以使用spring.cloud.gateway.default-filters。该属性使用一个过滤器列表(list)。下面示例设置一个默认过滤器集合(set):

1
2
3
4
5
6
spring:
cloud:
gateway:
default-filters:
- AddResponseHeader=X-Response-Default-Red, Default-Blue
- PrefixPath=/httpbin

全局过滤器

GlobalFilter 接口与 GatewayFilterFactory 系列过滤器有着相同的签名。 实现 GlobalFilter接口的过滤器是特殊过滤器,有条件地应用于所有路由。

所有全局过滤器都实现了 GlobalFilterOrdered,重写了 getOrder()filter(ServerWebExchange exchange, GatewayFilterChain chain)方法。

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

组合全局和网关过滤器排序

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

Spring Cloud Gateway 会区分过滤器逻辑执行的 pre(前置) 和 post(后置) 阶段,最高优先级的过滤器在 pre(前置)阶段是第一个执行,在post阶段是最后执行。查看 How it Works

下面示例配置一个过滤器链:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@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;
}
}

ForwardRoutingFilter

ForwardRoutingFilter转发路由过滤器:会在 Exchange 属性 ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR 中查找 RUI。如果 URIforward 模式(例如,forward:///localendpoint),它使用 Spring DispatcherHandler 来处理请求。请求 URI 中的 path 部分会被转发(forward) URL 中的 path 重写。

未修改的原始URL会附加到ServerWebExchangeUtils.GATEWAY_ORIGINAL_REQUEST_URL_ATTR属性中的列表中。

ForwardPathFilter

ForwardPathFilter从路由在获取 path,替换请求中的 path

LoadBalancerClientFilter

LoadBalancerClientFilter负载均衡过滤器(已被标记弃用,使用 ReactiveLoadBalancerClientFilter)。

会在 Exchange 属性ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR中查找 URI。如果 URIlb 模式(例如,lb://myservice),它会使用 Spring Cloud LoadBalancerClient 来将名称(示例是 myservice)解析成真实的 hostport,并替换请求的 URI。

未修改的原始 URL会附加到 ServerWebExchangeUtils.GATEWAY_ORIGINAL_REQUEST_URL_ATTR属性列表中。过滤器也会在 ServerWebExchangeUtils.GATEWAY_SCHEME_PREFIX_ATTR 属性列表中查找 URI 前缀是否等于lb ,如果是,则应用负载均衡规则。如下所示:

application.yml

1
2
3
4
5
6
7
8
spring:
cloud:
gateway:
routes:
- id: myRoute
uri: lb://service
predicates:
- Path=/service/**

注意:默认情况下,如果负载均衡器 LoadBalancer 找不到服务实例,则返回 503状态码。可以通过 设置spring.cloud.gateway.loadbalancer.use404=true 来配置网关返回 404

注意:从负载均衡器 (LoadBalancer) 返回的服务实例(ServiceInstance)的 isSecure 的值将覆盖对网关的请求中指定的模式(scheme)。
例如,进入网关的请求是 HTTPS,但服务实例声明并不是安全的,下游服务通过 HTTP访问。相反的情况也可以适用。然后,如果在 Gateway 配置中指定了路由的 GATEWAY_SCHEME_PREFIX_ATTR ,前缀将被删除,被删除后的路由 URL 将覆盖服务实例中的配置。

警告:LoadBalancerClientFilter 的低庋使用阻塞(blocking)的 Ribbon LoadBalancerClient。 建议您改用ReactiveLoadBalancerClientFilter。 可以通过将spring.cloud.loadbalancer.ribbon.enabled的值设置为false来切换到它。

ReactiveLoadBalancerClientFilter

LoadBalancerClientFilter响应式负载均衡过滤器:会查找 Exchange 中名为 ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR的属性。如果 URL 是 lb 模式(例如,lb://myservice),它使用 Spring Cloud ReactorLoadBalancer 来把服务名(示例中是 myservice)解析为真实的主机(host)和端口(port),并替换同一属性的 URI。未修改的原始 URL 被附加到 ServerWebExchangeUtils.GATEWAY_ORIGINAL_REQUEST_URL_ATTR 属性列表中。

过滤器还会在 ServerWebExchangeUtils.GATEWAY_SCHEME_PREFIX_ATTR 属性中查找其是否等于 lb。如果题,则应用相同的规则。配置示例如下:

application.yml

1
2
3
4
5
6
7
8
spring:
cloud:
gateway:
routes:
- id: myRoute
uri: lb://service
predicates:
- Path=/service/**

注意:默认情况下,如果负载均衡器 ReactorLoadBalancer 找不到服务实例(ServiceInstance),则返回 503状态码。可以通过主,以置spring.cloud.gateway.loadbalancer.use404=true 来配置网关返回 404

注意:从负载均衡器 (ReactiveLoadBalancerClientFilter ) 返回的服务实例(ServiceInstance)的 isSecure 的值将覆盖对网关的请求中指定的模式(scheme)。
例如,进入网关的请求是 HTTPS,但服务实例声明并不是安全的,下游服务通过 HTTP访问。相反的情况也可以适用。然后,如果在 Gateway 配置中指定了路由的 GATEWAY_SCHEME_PREFIX_ATTR ,前缀将被删除,被删除后的路由 URL 将覆盖服务实例中的配置。

NoLoadBalancerClientFilter

NoLoadBalancerClientFilterGatewayNoLoadBalancerClientAutoConfiguration 的一个内部静态类,被自动注册为 Bean。

处理非负载均衡模式的请求。会从 ServerWebExchange 的属性列表中获取 GATEWAY_REQUEST_URL_ATTRGATEWAY_SCHEME_PREFIX_ATTR 的值,判断 URL 的 Scheme 和 前缀是否等于 lb,如果都不相等,非负载均衡请求,则继续往下走。

Netty Routing Filter

NettyRoutingFilterHTTP或HTTPS请求协议路由过滤器: 如果位于 ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR Exchange 属性中的 URLhttphttps 方案,则将运行 Netty 路由过滤器。 它使用 Netty HttpClient 代理转发到下游的请求。

响应被放入ServerWebExchangeUtils.CLIENT_RESPONSE_ATTR Exchange 属性中,以供后续的过滤器使用。 (还有一个实验性的 WebClientHttpRoutingFilter 执行相同的功能,但不需要 Netty)。

Netty Write Response Filter

NettyWriteResponseFilter重写 Netty HTTP 响应过滤器: 如果 Exchange 的 ServerWebExchangeUtils.CLIENT_RESPONSE_ATTR属性中存在Netty HttpClientResponse,则NettyWriteResponseFilter 将运行。

它在所有其他过滤器完成后运行,并将代理响应写回到网关客户端响应。 (还有一个实验性的 WebClientWriteResponseFilter 执行相同的功能,但不需要 Netty)。

RouteToRequestUrl Filter

RouteToRequestUrlFilter将请求的 URL 替换为 Route 中的 URL:如果 Exchange 的ServerWebExchangeUtils.GATEWAY_ROUTE_ATTR Exchange 属性中有一个Route对象,则RouteToRequestUrlFilter 将运行。

它基于请求 URI 创建一个 新URI,但使用 Route 对象的 URI 属性进行更新。 新的URI 放置在ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR Exchange 属性中。

如果 URI 具有前缀模式(例如 lb:ws://serviceid),则将从 URI 中剥离 lb,并将其放置在ServerWebExchangeUtils.GATEWAY_SCHEME_PREFIX_ATTR中,以供后续的过滤器链使用。

Websocket Routing Filter

WebsocketRoutingFilter Websocket 路由过滤器:如果位于ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR Exchange 属性中的 URL 具有 wswss 模式,则将运行 websocket 路由过滤器。 它使用 Spring WebSocket 基础结构向下游转发 websocket 请求。

还可以通过 URI 前缀 lb 对 websockets 进行负载均衡,例如,lb:ws//serviceid

注意:如果使用 SockJS 作为普通 HTTP 的回退,则应配置普通HTTP 路由 和 websocket 路由。

下面是 websocket 路由过滤器的配置示例:

application.yml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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/**

Gateway Metrics Filter

GatewayMetricsFilter 网关监控/指标过滤器:要启用网关 监控/指标,添加spring-boot-starter-actuator依赖。然后,默认情况下,只要属性spring.cloud.gateway.metrics.enabled未设置为 false,网关 监控/指标 过滤器就会运行。

此过滤器添加名为 gateway.requests 的计时器监控/指标,其标记如下:

  • routeId: 路由 ID
  • routeUri: 路由到 API 的 URI
  • outcome: 效果, 按 HttpStatus.Series 分类
  • status: 返回给客户端的请求的HTTP状态(HTTP status)
  • httpStatusCode: 返回给客户端的请求的HTTP状态(HTTP Status)
  • httpMethod: HTTP 请求方式

然后,可以从 /actuator/metrics/gateway.requests 中获取这些监控/指标,并且可以很容易地与Prometheus集成以创建 Grafana仪表板。

注意:要启用 Prometheus 端点,需要引入 micrometer-registry-prometheus 依赖。

RemoveCachedBodyFilter

RemoveCachedBodyFilter移除保存在 ServerWebExchange 属性列表中的 请求缓存体

Marking An Exchange As Routed

标记 Exchange 为已路由:网关已经路由ServerWebExchange之后,通过将gatewayAlreadyRouted添加到 Exchange 属性列表中来将 Exchange 标记为 已路由(routed),其他路由过滤器将不会再次路由请求,实质上会跳过路由过滤器。

可以使用多种便捷方法将交换标记为已路由,或者检查交换是否已路由。

  • ServerWebExchangeUtils.isAlreadyRouted 接收一个ServerWebExchange 对象,并检测它是否已被路由(routed)。
  • ServerWebExchangeUtils.setAlreadyRouted 接收一个 ServerWebExchange 对象,并将其标记为已路由(routed)。

HTTP头过滤器

HttpHeadersFilter 在向下游服务发送请求之前应用于请求,例如在 NettyRoutingFilter中。

实现 HttpHeadersFilterOrdered 的过滤器重写 getOrder()filter(HttpHeaders input, ServerWebExchange exchange) 方法。

ForwardedHeadersFilter

ForwardedHeadersFilter(转发)头过滤器创建一个 Forwarded头以发送到下游服务。 它将当前请求的host头,schemeport添加到任何现有的Forward头中。

RemoveHopByHopHeadersFilter

RemoveHopByHopHeadersFilter头过滤器移除转发(forwarded)请求的头。被删除的头的默认列表来自 IETF。

配置属性:spring.cloud.gateway.filter.remove-hop-by-hop

默认移除的头有:

  • Connection
  • Keep-Alive
  • Proxy-Authenticate
  • Proxy-Authorization
  • TE
  • Trailer
  • Transfer-Encoding
  • Upgrade

要更改此设置,将spring.cloud.gateway.filter.remove-non-proxy-headers.headers属性设置为要删除的标头名称列表。

XForwardedHeadersFilter

XForwardedHeadersFilter头过滤器创建各种 X-Forwarded-* 头来发给下游服务。使用当前请求的host头,scheme, port, path来创建。配置属性:spring.cloud.gateway.x-forwarded

可以通过以下布尔属性(默认为 true)控制单个头的创建:

  • spring.cloud.gateway.x-forwarded.for.enabled
  • spring.cloud.gateway.x-forwarded.host.enabled
  • spring.cloud.gateway.x-forwarded.port.enabled
  • spring.cloud.gateway.x-forwarded.proto.enabled
  • spring.cloud.gateway.x-forwarded.prefix.enabled

可以通过以下布尔属性(默认为 true)控制追加多个标头:

  • spring.cloud.gateway.x-forwarded.for.append
  • spring.cloud.gateway.x-forwarded.host.append
  • spring.cloud.gateway.x-forwarded.port.append
  • spring.cloud.gateway.x-forwarded.proto.append
  • spring.cloud.gateway.x-forwarded.prefix.append

Spring Cloud(二十):Gateway 路由匹配表达式工厂,过滤器工厂,全局过滤器,HTTP头过滤器

http://blog.gxitsky.com/2020/03/13/SpringCloud-20-gateway-route-filter-global-headers/

作者

光星

发布于

2020-03-13

更新于

2022-06-17

许可协议

评论