114. Route 谓词工厂

Spring Cloud Gateway 将路由作为 Spring WebFlux HandlerMapping基础架构的一部分进行匹配。 Spring Cloud Gateway 包括许多内置的 Route Predicate 工厂。所有这些谓词都与 HTTP 请求的不同属性匹配。多个路由谓词工厂可以组合,并通过逻辑and进行组合。

114.1 Route Predicate Factory 之后

路由后谓词工厂采用一个参数,即日期时间。该谓词匹配在当前日期时间之后发生的请求。

application.yml.

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

此 Route 与 2017 年 1 月 20 日 17:42 山区时间(丹佛)之后的所有请求匹配。

114.2 Route Predicate Factory 之前

路由谓词前工厂采用一个参数,即日期时间。该谓词匹配当前日期时间之前发生的请求。

application.yml.

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

此 Route 与 2017 年 1 月 20 日 17:42 山区时间(丹佛)之前的所有请求匹配。

114.3 路由谓词工厂之间

路由谓词间工厂之间采用两个参数 datetime1 和 datetime2.该谓词匹配在 datetime1 之后和 datetime2 之前发生的请求。 datetime2 参数必须在 datetime1 之后。

application.yml.

spring:
  cloud:
    gateway:
      routes:
      - id: between_route
        uri: http://example.org
        predicates:
        - Between=2017-01-20T17:42:47.789-07:00[America/Denver], 2017-01-21T17:42:47.789-07:00[America/Denver]

此 Route 与 2017 年 1 月 20 日山区时间(丹佛)之后和 2017 年 1 月 21 日 17:42 山时间(丹佛)之后的任何请求匹配。这对于维护时段可能很有用。

114.4 CookieRoute 谓词工厂

Cookie Route Predicate Factory 采用两个参数,即 cookie 名称和正则表达式。该谓词匹配具有给定名称的 cookie,并且值匹配正则表达式。

application.yml.

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

此路由与请求匹配,并具有一个名为chocolate的 cookie,该 cookie 的值与ch.p正则表达式匹配。

114.5Headers 路由谓词工厂

Headers 路由谓词工厂采用两个参数,Headers 名称和正则表达式。该谓词与具有给定名称的 Headers 匹配,并且值与正则表达式匹配。

application.yml.

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

如果请求的标题为X-Request-Id,而其值与\d+正则表达式匹配(具有一个或多个数字的值),则此路由匹配。

114.6 主机路由谓词工厂

主机路由谓词工厂采用一个参数:主机名模式列表。该模式是以.作为分隔符的 Ant 样式模式。该谓词匹配与模式匹配的HostHeaders。

application.yml.

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

还支持 URI 模板变量,例如{sub}.myhost.org

如果请求的HostHeaders 的值为www.somehost.orgbeta.somehost.orgwww.anotherhost.org,则此路由将匹配。

该谓词提取 URI 模板变量(如上例中定义的sub)作为名称和值的 Map,并使用ServerWebExchangeUtils.URI_TEMPLATE_VARIABLES_ATTRIBUTE中定义的键将其放在ServerWebExchange.getAttributes()中。这些值随后可供GatewayFilter Factories使用

114.7 方法 Route 谓词工厂

方法路由谓词工厂使用一个参数:要匹配的 HTTP 方法。

application.yml.

spring:
  cloud:
    gateway:
      routes:
      - id: method_route
        uri: http://example.org
        predicates:
        - Method=GET

如果请求方法是GET,则此路由将匹配。

114.8 路径路由谓词工厂

路径路由谓词工厂采用两个参数:Spring PathMatcher模式列表和matchOptionalTrailingSeparator的可选标志。

application.yml.

spring:
  cloud:
    gateway:
      routes:
      - id: host_route
        uri: http://example.org
        predicates:
        - Path=/foo/{segment},/bar/{segment}

如果请求路径为/foo/1/foo/bar/bar/baz,则此路由将匹配。

该谓词提取 URI 模板变量(如上例中定义的segment)作为名称和值的 Map,并使用ServerWebExchangeUtils.URI_TEMPLATE_VARIABLES_ATTRIBUTE中定义的键将其放在ServerWebExchange.getAttributes()中。这些值随后可供GatewayFilter Factories使用

可以使用 Util 方法来简化对这些变量的访问。

Map<String, String> uriVariables = ServerWebExchangeUtils.getPathPredicateVariables(exchange);

String segment = uriVariables.get("segment");

114.9 查询路由谓词工厂

查询路由谓词工厂采用两个参数:必需的param和可选的regexp

application.yml.

spring:
  cloud:
    gateway:
      routes:
      - id: query_route
        uri: http://example.org
        predicates:
        - Query=baz

如果请求包含baz查询参数,则此路由将匹配。

application.yml.

spring:
  cloud:
    gateway:
      routes:
      - id: query_route
        uri: http://example.org
        predicates:
        - Query=foo, ba.

如果请求包含一个foo查询参数,其值与ba.正则表达式匹配,则此路由将匹配,因此barbaz将匹配。

114.10 RemoteAddr 路由谓词工厂

RemoteAddr 路由谓词工厂采用 CIDR 标记(IPv4 或 IPv6)字符串的列表(最小大小为 1),例如192.168.0.1/16(其中192.168.0.1是 IP 地址,16是子网掩码)。

application.yml.

spring:
  cloud:
    gateway:
      routes:
      - id: remoteaddr_route
        uri: http://example.org
        predicates:
        - RemoteAddr=192.168.1.1/24

如果请求的远程地址为192.168.1.10,则此路由将匹配。

114.10.1 修改解析远程地址的方式

默认情况下,RemoteAddr 路由谓词工厂使用传入请求中的远程地址。如果 Spring Cloud Gateway 位于代理层后面,则此地址可能与实际的 Client 端 IP 地址不匹配。

您可以通过设置自定义RemoteAddressResolver来定制解析远程地址的方式。 Spring Cloud Gateway 随附了一个基于X-Forwarded-For headerXForwardedRemoteAddressResolver的非默认远程地址解析器。

XForwardedRemoteAddressResolver有两种静态构造方法,它们采用不同的安全性方法:

XForwardedRemoteAddressResolver::trustAll返回一个RemoteAddressResolver,该RemoteAddressResolver始终采用X-Forwarded-ForHeaders 中找到的第一个 IP 地址。这种方法容易受到欺骗的攻击,因为恶意 Client 端可能会为X-Forwarded-For设置初始值,解析器会接受该初始值。

XForwardedRemoteAddressResolver::maxTrustedIndex取得一个索引,该索引与 Spring Cloud Gateway 前面运行的受信任基础结构的数量相关。例如,如果只能通过 HAProxy 访问 Spring Cloud Gateway,则应使用值 1.如果在访问 Spring Cloud Gateway 之前需要两跳可信基础架构,则应使用值 2.

给定以下 Headers 值:

X-Forwarded-For: 0.0.0.1, 0.0.0.2, 0.0.0.3

下面的maxTrustedIndex值将产生以下远程地址。

maxTrustedIndexresult
[ 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

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