Skip to content

路由断言工厂 (Route Predicate Factories)

Spring Cloud Gateway 将路由匹配作为 Spring WebFlux HandlerMapping 基础设施的一部分。 Spring Cloud Gateway 包含许多内置的路由断言工厂。所有这些断言都匹配 HTTP 请求的不同属性。 你可以使用逻辑 and 语句组合多个路由断言工厂。

1. After 路由断言工厂

After 路由断言工厂接受一个参数:datetime(即 Java 的 ZonedDateTime)。 该断言匹配发生在指定日期时间之后的请求。

application.yml

yaml
spring:
  cloud:
    gateway:
      routes:
      - id: after_route
        uri: https://example.org
        predicates:
        - After=2017-01-20T17:42:47.789-07:00[America/Denver]

此路由匹配 2017 年 1 月 20 日 17:42(丹佛时间)之后发出的任何请求。

2. Before 路由断言工厂

Before 路由断言工厂接受一个参数:datetime(即 Java 的 ZonedDateTime)。 该断言匹配发生在指定日期时间之前的请求。

application.yml

yaml
spring:
  cloud:
    gateway:
      routes:
      - id: before_route
        uri: https://example.org
        predicates:
        - Before=2017-01-20T17:42:47.789-07:00[America/Denver]

此路由匹配 2017 年 1 月 20 日 17:42(丹佛时间)之前发出的任何请求。

3. Between 路由断言工厂

Between 路由断言工厂接受两个参数:datetime1datetime2(即 Java 的 ZonedDateTime 对象)。 该断言匹配发生在 datetime1 之后且 datetime2 之前的请求。datetime2 参数必须在 datetime1 之后。

application.yml

yaml
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]

此路由匹配 2017 年 1 月 20 日 17:42 到 2017 年 1 月 21 日 17:42(丹佛时间)之间发出的任何请求。 这对维护窗口期非常有用。

Cookie 路由断言工厂接受两个参数:Cookie name(名称)和 regexp(Java 正则表达式)。 该断言匹配具有给定名称且值与正则表达式匹配的 Cookie。

application.yml

yaml
spring:
  cloud:
    gateway:
      routes:
      - id: cookie_route
        uri: https://example.org
        predicates:
        - Cookie=chocolate, ch.p

此路由匹配请求中包含名为 chocolate 且值匹配 ch.p 正则表达式的 Cookie。

5. Header 路由断言工厂

Header 路由断言工厂接受两个参数:header(名称)和 regexp(Java 正则表达式)。 该断言匹配具有给定名称且值与正则表达式匹配的 Header。

application.yml

yaml
spring:
  cloud:
    gateway:
      routes:
      - id: header_route
        uri: https://example.org
        predicates:
        - Header=X-Request-Id, \d+

如果请求包含名为 X-Request-Id 的 Header,且其值匹配 \d+ 正则表达式(即值为一个或多个数字),则匹配该路由。

6. Host 路由断言工厂

Host 路由断言工厂接受一个参数:主机名 patterns(模式)列表。 该模式是 Ant 风格的模式,以 . 作为分隔符。 该断言匹配与模式匹配的 Host Header。

application.yml

yaml
spring:
  cloud:
    gateway:
      routes:
      - id: host_route
        uri: https://example.org
        predicates:
        - Host=**.somehost.org,**.anotherhost.org

同样支持 URI 模板变量(例如 {sub}.myhost.org)。

此路由匹配 Host Header 值为 www.somehost.orgbeta.somehost.orgwww.anotherhost.org 的请求。

该断言会将 URI 模板变量(如上例中定义的 sub)提取为名称和值的映射,并将其放入 ServerWebExchange.getAttributes() 中,键为 ServerWebExchangeUtils.URI_TEMPLATE_VARIABLES_ATTRIBUTE。 这些值随后可供 GatewayFilter 工厂 使用。

7. Method 路由断言工厂

Method 路由断言工厂接受一个 methods 参数,它可以是一个或多个参数:即要匹配的 HTTP 方法。

application.yml

yaml
spring:
  cloud:
    gateway:
      routes:
      - id: method_route
        uri: https://example.org
        predicates:
        - Method=GET,POST

如果请求方法是 GETPOST,则匹配该路由。

8. Path 路由断言工厂

Path 路由断言工厂接受两个参数:Spring PathMatcher patterns(模式)列表和一个可选的标志 matchTrailingSlash(默认为 true)。

application.yml

yaml
spring:
  cloud:
    gateway:
      routes:
      - id: path_route
        uri: https://example.org
        predicates:
        - Path=/red/{segment},/blue/{segment}

此路由匹配路径为 /red/1/red/1//red/blue/blue/green 的请求。

如果 matchTrailingSlash 设置为 false,则请求路径 /red/1/ 将不会被匹配。

如果你设置了 spring.webflux.base-path 属性,它将影响路径匹配。该属性值将自动添加到路径模式之前。例如,如果 spring.webflux.base-path=/app 且路径模式为 /red/{segment},则用于匹配的完整模式将是 /app/red/{segment}

该断言会将 URI 模板变量(如上例中定义的 segment)提取为名称和值的映射,并将其放入 ServerWebExchange.getAttributes() 中,键为 ServerWebExchangeUtils.URI_TEMPLATE_VARIABLES_ATTRIBUTE。 这些值随后可供 GatewayFilter 工厂 使用。

可以使用一个工具方法(名为 get)来更轻松地访问这些变量:

java
Map<String, String> uriVariables = ServerWebExchangeUtils.getUriTemplateVariables(exchange);
String segment = uriVariables.get("segment");

9. Query 路由断言工厂

Query 路由断言工厂接受两个参数:一个必需的 param 和一个可选的 regexp(Java 正则表达式)。

application.yml

yaml
spring:
  cloud:
    gateway:
      routes:
      - id: query_route
        uri: https://example.org
        predicates:
        - Query=green

如果请求包含 green 查询参数,则匹配上述路由。

application.yml

yaml
spring:
  cloud:
    gateway:
      routes:
      - id: query_route
        uri: https://example.org
        predicates:
        - Query=red, gree.

如果请求包含名为 red 的查询参数,且其值匹配 gree. 正则表达式(例如 greengreet),则匹配上述路由。

10. RemoteAddr 路由断言工厂

RemoteAddr 路由断言工厂接受一个 sources 列表(最小大小为 1),即 CIDR 符号(IPv4 或 IPv6)字符串,例如 192.168.0.1/16(其中 192.168.0.1 是 IP 地址,16 是子网掩码)。

application.yml

yaml
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 来定义远程地址的解析方式。 Spring Cloud Gateway 提供了一个非默认的远程地址解析器 XForwardedRemoteAddressResolver,它基于 X-Forwarded-For header

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。

考虑以下 Header 值:

X-Forwarded-For: 0.0.0.1, 0.0.0.2, 0.0.0.3

以下 maxTrustedIndex 值将产生以下远程地址:

maxTrustedIndex结果
[Integer.MIN_VALUE, 0](无效, 初始化时抛出 IllegalArgumentException)
10.0.0.3
20.0.0.2
30.0.0.1
[4, Integer.MAX_VALUE]0.0.0.1

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

GatewayConfig.java

java
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")
)

11. Weight 路由断言工厂

Weight 路由断言工厂接受两个参数:groupweight(一个整数)。权重是按组计算的。

application.yml

yaml
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。

12. XForwarded Remote Addr 路由断言工厂

XForwarded Remote Addr 路由断言工厂接受一个 sources 列表(最小大小为 1),即 CIDR 符号(IPv4 或 IPv6)字符串,例如 192.168.0.1/16

此路由断言允许基于 X-Forwarded-For HTTP Header 过滤请求。

这可以与反向代理(如负载均衡器或 Web 应用程序防火墙)一起使用,在这些场景中,只有当请求来自这些反向代理使用的受信任 IP 地址列表时,才允许请求通过。

application.yml

yaml
spring:
  cloud:
    gateway:
      routes:
      - id: xforwarded_remoteaddr_route
        uri: https://example.org
        predicates:
        - XForwardedRemoteAddr=192.168.1.1/24

如果 X-Forwarded-For Header 包含(例如)192.168.1.10,则匹配该路由。

个人笔记

(先记住一句话:所谓 Predicate 就是“请求满足什么条件才走这条路由”——相当于安检门的“准入规则”。)


1. 时间三兄弟:After / Before / Between

名字作用一句话记忆例子
After只有在“这个时间点之后”来的请求才放行过了点才开门- After=2025-06-01T00:00:00+08:00[Asia/Shanghai]
Before只有在“这个时间点之前”来的请求才放行过期不候同上,把 After 换成 Before
Between只有在“这两时间点之间”来的请求才放行限时开放- Between=2025-06-01T00:00:00+08:00[Asia/Shanghai], 2025-06-03T23:59:59+08:00[Asia/Shanghai]

时间格式固定:yyyy-MM-dd'T'HH:mm:ss.SSSXXX[时区],直接抄示例改数字最稳。


作用:请求必须带指定 Cookie 名 + 值匹配正则 才放行。
例子

yaml
- Cookie=session, \d+      # 必须带名为 session 的 Cookie,且值是纯数字

生活场景:门禁卡必须写着你名字并且号码是“数字”才让你进。


3. Header 检查官

作用:请求头必须存在某 key + 值匹配正则
例子

yaml
- Header=X-Request-Id, \d+   # 请求头里要有 X-Request-Id 且值是数字

生活场景:安检要看你工牌编号是不是“数字”。


4. Host 域名匹配

作用:根据 Host 头 做“模糊匹配”。
例子

yaml
- Host=**.api.example.com   # 任何三级域名都可:foo.api.example.com、bar.api.example.com

生活场景:公司园区有多个门,只要门牌后缀是 .api.example.com 都能进。


5. Method 方法匹配

作用:只允许指定 HTTP 方法
例子

yaml
- Method=GET,POST           # 只接 GET 或 POST,PUT/DELETE 直接 404

6. Path 路径匹配(最常用)

作用:根据 URL 路径 做匹配,还能顺手提取变量
例子

yaml
- Path=/order/{orderId}/detail    # 匹配 /order/123/detail,同时把 123 存进变量 orderId

高级开关
matchTrailingSlash=false/order/123/ 不匹配(默认是 true,带不带斜杠都算)。


7. Query 参数匹配

作用:要求必须带某个 查询参数,可附加正则。
例子

yaml
- Query=green               # 只要有 ?green 就行,值无所谓
- Query=red, gree.          # 必须带 ?red=xxx 且值满足正则 gree.(如 green、greet)

8. RemoteAddr / XForwardedRemoteAddr

作用:只看 客户端 IP 是否落在指定网段。
区别

  • RemoteAddr:直接拿 TCP 连接 IP,网关前面没代理才准。
  • XForwardedRemoteAddr:拿 X-Forwarded-For 头,前面有 Nginx / SLB 时必须用它。

例子

yaml
- RemoteAddr=192.168.1.0/24        # 只允许 192.168.1.* 网段

配合代理

java
// Java 配置示例:信任前面只有 1 层代理
RemoteAddressResolver resolver = XForwardedRemoteAddressResolver
                                .maxTrustedIndex(1);

9. Weight 权重分流

作用:把流量按权重分到不同后端,做灰度 / A/B
例子

yaml
# 80% 流量去 weighthigh.org
- id: weight_high
  predicates:
  - Weight=group1, 8

# 20% 流量去 weightlow.org
- id: weight_low
  predicates:
  - Weight=group1, 2

生活场景:10 张抽奖券,8 张写 A 奖,2 张写 B 奖,随机抽。


10. 组合使用(AND 关系)

一句话同一路由里多个 predicate 默认是“且”关系
例子

yaml
predicates:
- Path=/api/**
- Method=POST
- Header=X-Version, v2

含义:只有 POST 方式 访问 /api/** X-Version:v2 头,才走这条路由。


速查表(保存即可)

场景直接抄
限定时间窗口- Between=2025-06-01T00:00:00+08:00[Asia/Shanghai], 2025-06-03T23:59:59+08:00[Asia/Shanghai]
必须带某 Cookie- Cookie=session, \d+
只接 GET- Method=GET
提取路径变量- Path=/user/{userId}
只允许内网 IP- RemoteAddr=10.0.0.0/8
80%/20% 灰度两条路由,分别 - Weight=group1, 8- Weight=group1, 2

最后口诀

“时间用 After,灰度用 Weight,路径变量用 Path,IP 限制看 Remote,其他 Header Cookie Query 都能拦。”

拿着这张速查表,10 秒钟就能写出一条新路由。

Based on Spring Framework.