启动cloud-gateway-gateway9527项目控制台会打印出入如下内容,说明有如下几种断言规则
image.png

介绍

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

Spring Cloud Gateway创建 Route 对象时,使用 RoutePredicateFactor 创建 Predicate 对象,Predicate对象可以赋值给Route。Spring Cloud Gateway 包含许多内置的Route Predicate Factories

所有这些谓词都匹配HTTP请求的不同属性。多种谓词工厂可以组合,并通过逻辑and。

1.The After Route Predicate Factory

After路由 predicate 工厂接受一个参数,一个datetime(它是一个java ZonedDateTime)。此 predicate 匹配在指定日期时间之后发生的请求。下面的示例配置一个after路由predicate:

例1。application.yml

  1. spring:
  2. cloud:
  3. gateway:
  4. routes:
  5. - id: after_route
  6. uri: lb://cloud-payment-service #此处需要使用lb协议才能根据服务名进行负载均衡调用
  7. predicates:
  8. - After=2017-01-20T17:42:47.789-07:00[America/Denver]

这条路由与丹佛时间2017年1月20日17点42分以后的任何请求相匹配。

以上是日期格式是国外的时区,可以用以下代码获取本地时区

ZonedDateTime zonedDateTime = ZonedDateTime.now();
System.out.println(zonedDateTime);
// 输出:2020-04-30T15:48:20.500+08:00[Asia/Shanghai]

2.The Before Route Predicate Factory

Before路由 predicate 工厂接受一个参数,一个datetime(它是一个java ZonedDateTime)。此 predicate 匹配在指定日期时间之前发生的请求。下面的示例配置一个before路由 predicate:

例2. application.ym

spring:
  cloud:
    gateway:
      routes:
      - id: before_route
        uri: lb://cloud-payment-service #此处需要使用lb协议才能根据服务名进行负载均衡调用
        predicates:
        - Before=2017-01-20T17:42:47.789-07:00[America/Denver]

这条路由与丹佛时间2017年1月20日17点42分之前的任何请求相匹配。

3.The Between Route Predicate Factory

route predicate工厂接受两个参数,datetime1和datetime2,它们是java ZonedDateTime对象。此predicate匹配在datetime1之后和datetime2之前发生的请求。datetime2参数必须位于datetime1之后。下面的示例配置一个路由间predicate:

例3. application.yml

spring:
  cloud:
    gateway:
      routes:
      - id: between_route
        uri: lb://cloud-payment-service #此处需要使用lb协议才能根据服务名进行负载均衡调用
        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山地时间之前的任何请求匹配。这对于维护窗口可能很有用。

4.The Cookie Route Predicate Factory

Cookie route predicate工厂接受两个参数,Cookie名称和regexp(它是一个Java正则表达式)。此predicate匹配具有给定名称且其值与正则表达式匹配的cookie。下面的示例配置一个cookie路由谓词工厂:

例4. application.yml

spring:
  cloud:
    gateway:
      routes:
      - id: cookie_route
        uri: lb://cloud-payment-service #此处需要使用lb协议才能根据服务名进行负载均衡调用
        predicates:
        - Cookie=chocolate, ch.p

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

使用cURL工具发送带有cookie为chocolate=ch.p的请求可以匹配该路由。

curl http://localhost:9527/payment/lb/ --cookie "chocolate=ch.p"


5.The Header Route Predicate Factory

头 route predicate 工厂接受两个参数,头名称和regexp(这是一个Java正则表达式)。此predicate与具有给定名称且其值与正则表达式匹配的头匹配。以下示例配置头route predicate:

例 5. application.yml

spring:
  cloud:
    gateway:
      routes:
      - id: header_route
        uri: lb://cloud-payment-service #此处需要使用lb协议才能根据服务名进行负载均衡调用
        predicates:
        - Header=X-Request-Id, \d+

如果请求的头名为X-Request-Id,其值与\d+正则表达式匹配(即,它的值为一个或多个数字),则此路由将进行匹配。

使用cURL发送带有请求头为X-Request-Id:123的请求可以匹配该路由。

curl http://localhost:9527/payment/lb/ -H "X-Request-Id:123"

6.The Host Route Predicate Factory

Host route predicate工厂需要一个参数:主机名的列表 patterns .的模式是一个Ant-style的模式,. 作为分隔符。此 predicate 与模式匹配的主机标头匹配。下面的示例配置一个Host route predicate:

例6. application.yml

spring:
  cloud:
    gateway:
      routes:
      - id: host_route
        uri: lb://cloud-payment-service #此处需要使用lb协议才能根据服务名进行负载均衡调用
        predicates:
        - Host=**.somehost.org,**.anotherhost.org

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

如果请求的主机头的值为www.somehost.org或beta.somehost.org或www.anotherhost.org,则此路由匹配。

此predicate将URI模板变量(如前面示例中定义的sub)提取为名称和值的映射,并将其放在ServerWebExchange.getAttributes()中,并在ServerWebExchangeUtils.URI_TEMPLATE_VARIABLES_ATTRIBUTE中定义了一个键。然后这些值可供GatewayFilter factories使用

使用cURL访问带有请求头为www.somehost.org或者www.anotherhost.org的请求可以匹配该路由。

curl http://localhost:9527/payment/lb/ -H "Host:www.somehost.org"

7.The Method Route Predicate Factory

Method Route Predicate工厂接受一个methods 参数,该参数是一个或多个参数:要匹配的HTTP methods。下面的示例配置一个方法route predicate:
例7. application.yml

spring:
  cloud:
    gateway:
      routes:
      - id: method_route
        uri: lb://cloud-payment-service #此处需要使用lb协议才能根据服务名进行负载均衡调用
        predicates:
        - Method=GET,POST

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

使用cURL发送GET或POST请求可以匹配该路由。

curl http://localhost:9527/payment/lb/

8.The Path Route Predicate Factory

Path Route Predicate工厂接受两个参数:一个Spring PathMatcher patterns 和一个名为matchOptionalTrailingSeparator的可选标志。下面的示例配置一个path route predicate:

例8. application.yml

spring:
  cloud:
    gateway:
      routes:
      - id: path_route
        uri: lb://cloud-payment-service #此处需要使用lb协议才能根据服务名进行负载均衡调用
        predicates:
        - Path=/red/{segment},/blue/{segment}

如果请求路径为,例如:/red/1 或/red/blue/blue/green,则此路由匹配。

该predicate将URI模板变量(如前面示例中定义的segment)提取为名称和值的映射,并将其放入ServerWebExchange.getAttributes()中,并在ServerWebExchangeUtils.URI_TEMPLATE_VARIABLES_ATTRIBUTE.中定义了一个键。然后这些值可供GatewayFilter factories使用

有一个实用方法(称为get)可以使访问这些变量变得更容易。下面的示例演示如何使用get方法:

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

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

9.The Query Route Predicate Factory

Query route predicate工厂接受两个参数:一个必需的param 和一个可选的regexp (它是一个Java正则表达式)。下面的示例配置一个查询路由谓词:

例9. application.yml

spring:
  cloud:
    gateway:
      routes:
      - id: query_route
        uri: lb://cloud-payment-service #此处需要使用lb协议才能根据服务名进行负载均衡调用
        predicates:
        - Query=green

如果请求包含green 查询参数,则前面的路由匹配。

application.yml

spring:
  cloud:
    gateway:
      routes:
      - id: query_route
        uri: lb://cloud-payment-service #此处需要使用lb协议才能根据服务名进行负载均衡调用
        predicates:
        - Query=red, gree.

如果请求包含一个red 查询参数,其值与gree. 匹配,则前面的路由将匹配。regexp,所以green和greet 是匹配的。

使用curl发送带Query=red查询参数的请求可以匹配该路由。

curl http://localhost:9527/payment/lb/?red=greet

10.The RemoteAddr Route Predicate Factory

RemoteAddr route predicate 工厂接受 sources 列表(最小大小为1),这些源是CIDR符号(IPv4或IPv6)字符串,比如192.168.0.1/16(其中192.168.0.1是一个IP地址,16 是子网掩码)。下面的示例配置一个RemoteAddr route predicate:

例10. application.yml

spring:
  cloud:
    gateway:
      routes:
      - id: remoteaddr_route
        uri: lb://cloud-payment-service #此处需要使用lb协议才能根据服务名进行负载均衡调用
        predicates:
        - RemoteAddr=192.168.1.1/24

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

11.The Weight Route Predicate Factory

权重 route predicate工厂接受两个参数:组和权值(一个int)。每组计算权重。下面的示例配置一个权重route predicate:

例11. application.yml

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

这条 route 将80%的流量转发到weigh.org, 20%的流量转发到weighlow.org

11.1.修改远程地址解析的方式

默认情况下,RemoteAddr route predicate工厂使用来自传入请求的远程地址。如果Spring Cloud Gateway位于代理层的后面,这可能与实际的客户端IP地址不匹配。

您可以通过设置自定义RemoteAddressResolver来自定义远程地址的解析方式。Spring Cloud Gateway提供了一个非默认的远程地址解析器,它基于X-Forwarded-For header,XForwardedRemoteAddressResolver。

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

  1. XForwardedRemoteAddressResolver::trustAll 返回一个RemoteAddressResolver,它总是接受X-Forwarded-For头中找到的第一个IP地址。这种方法容易受到欺骗,因为恶意客户机可以为X-Forwarded-For设置一个初始值,解析器将接受这个初始值。
  2. XForwardedRemoteAddressResolver::maxTrustedIndex 获取与运行在Spring Cloud Gateway前的可信基础设施数量相关的索引。例如,如果Spring Cloud Gateway只能通过HAProxy访问,那么应该使用值1。如果在访问Spring Cloud Gateway之前需要两个可信基础设施的跃点,那么应该使用值2。

考虑以下头值:

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实现相同的配置:

例12. 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")
)