网关 Spring Cloud Gateway 内置的路由谓词工厂详解(最全的路由策略11种)


💨 作者:laker,因为喜欢LOL滴神faker,又是NBA湖人队🏀(laker)粉丝儿(主要是老詹的粉丝儿),本人又姓,故取笔名:laker
❤️喜欢分享自己工作中遇到的问题和解决方案以及一些读书笔记和心得分享
🌰本人创建了微信公众号【Java大厂面试官】,用于和大家交流分享
🏰 个人微信【lakernote】,加作者备注下暗号:cv之道


本文Spring Cloud Gateway 版本:2020.0.0

Spring Cloud Gateway将路由作为Spring WebFluxHandlerMapping基础架构的一部分进行匹配。Spring Cloud Gateway包括许多内置的路由谓词工厂。所有这些谓词都与HTTP请求的不同属性匹配。您可以将多个路由谓词工厂与逻辑and语句结合使用。

路由谓词工厂的作用是:符合Predicate的条件,就使用该路由的配置,否则就不予处理。(可以多种路由谓词工厂自由搭配很全面)

官网地址:https://cloud.spring.io/spring-cloud-gateway/reference/html/#configuring-route-predicate-factories-and-gateway-filter-factories

全部内置(11种)的路由谓词工厂:

路由谓词工厂Http协议匹配字段备注
After请求时间不常用
Before请求时间不常用
Between请求时间不常用
CookieCookie常用
HeaderHeader常用
HostHost不常用
MethodMethod不常用
Path路径常用
Query参数常用
RemoteAddr请求远程地址IP不常用
Weight基于路由权重不常用

在这里插入图片描述

After路由谓词工厂

After路由谓词工厂有一个参数,一个datetime(其实是Java 的ZonedDateTime)。该谓词匹配在指定日期时间之后发生的请求。下面的示例配置路由后谓词:

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山区时间(丹佛)之后的任何请求。

这个基本用不到,可以不细研究,ZonedDateTime.now()

Before路由谓词工厂

Before路由谓词工厂有一个参数,一个datetime(其实Java ZonedDateTime)。该谓词匹配在指定之前发生的请求datetime。下面的示例配置路由前谓词:

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山区时间(丹佛)之前的任何要求。

这个基本用不到,可以不细研究,ZonedDateTime.now()

Between路由谓词工厂

Between路由谓词工厂有两个参数,datetime1datetime2 都是JavaZonedDateTime对象。该谓词匹配之后datetime1和之前发生的请求datetime2。该datetime2参数必须是后datetime1。以下示例配置了路由之间的谓词:

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日山区时间(丹佛)之后和2017年1月21日17:42山区时间(丹佛)之后的任何请求相匹配。这对于维护时段可能很有用。

这个基本用不到,可以不细研究,ZonedDateTime.now()

Cookie路由谓词工厂

Cookie路由谓词工厂采用两个参数,cookienameregexp(其是Java正则表达式)。该谓词匹配具有给定名称且其值与正则表达式匹配的cookie。以下示例配置cookie路由谓词工厂:

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

此路由匹配具有Cookie的请求,该Cookie的名称chocolatech.p正则表达式匹配。

当且仅当带有名为somecookie,并且值符合正则ch.p的Cookie时,才会转发到用户微服务

Header路由谓词工厂

Header路由谓词工厂采用两个参数,headername和一个regexp(其是Java正则表达式)。该谓词与具有给定名称的标头匹配,该标头的值与正则表达式匹配。以下示例配置标头路由谓词:

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

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

当且仅当带有名为X-Request-Id,并且值符合正则\d+的Header时,才会转发到用户微服务

使用 curl 测试,命令行输入:

curl http://localhost:8080 -H "X-Request-Id:88"

则返回页面代码证明匹配成功。将参数-H "X-Request-Id:88"改为-H "X-Request-Id:spring"再次执行时返回404证明没有匹配

Host路由谓词工厂

Host路由谓词工厂需要一个参数:主机名的列表patterns。该模式是带有.分隔符的Ant样式的模式。谓词与Host匹配模式的标头匹配。以下示例配置主机路由谓词:

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

当且仅当名为Host的Header符合**.somehost.org或**.anotherhost.org时,才会转发用户微服务

{sub}.myhost.org还支持URI模板变量。

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

该谓词提取URI模板变量(例如sub,在前面的示例中定义的)作为名称和值的映射,并ServerWebExchange.getAttributes()使用中定义的键将其放在中ServerWebExchangeUtils.URI_TEMPLATE_VARIABLES_ATTRIBUTE。这些值可供工厂使用GatewayFilter

Method路由谓词工厂

Method路由谓词厂需要methods的参数,它是一个或多个参数:HTTP方法来匹配。以下示例配置方法route谓词:

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

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

Path路由谓词工厂

Path路由谓词厂有两个参数:PathMatcher patterns和一个可选的标志叫matchOptionalTrailingSeparator。以下示例配置路径路由谓词:

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

匹配/red/1/red/blue/blue/green

该谓词提取URI模板变量(例如segment,在前面的示例中定义的)作为名称和值的映射,在ServerWebExchange.getAttributes()使用中定义的键将其放在ServerWebExchangeUtils.URI_TEMPLATE_VARIABLES_ATTRIBUTE。这些值可供工厂使用GatewayFilter

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

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

Query路由谓词工厂

Query路由谓词工厂采用两个参数:请求的param和可选的regexp(Java正则表达式)。以下示例配置查询路由谓词:

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

如果请求包含green查询参数,则前面的路由匹配。
使用 curl 测试,命令行输入:

curl localhost:8080?green=x&id=2

经过测试发现只要请求带有 green 参数即会匹配路由,不带 green参数则不会匹配。

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

如果请求包含一个参数匹配red,其值匹配gree.正则,所以greengreet都将匹配。

RemoteAddr路由谓词工厂

RemoteAddr路由谓词工厂参数,是CIDR的表示法(IPv4或IPv6)的字符串,如192.168.0.1/16(其中192.168.0.1是一个IP地址和16一个子网掩码)。以下示例配置一个RemoteAddr路由谓词:

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

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

Weight路由谓词工厂

Weight路由谓词工厂有两个参数:groupweight(一个int)。权重是按组计算的。以下示例配置权重路由谓词:

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。

修改远程地址的解析方式

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

您可以通过设置custom来定制解析远程地址的方式RemoteAddressResolverSpring Cloud Gateway附带了一个远程地址解析器 X-Forwarded-For header,XForwardedRemoteAddressResolver

XForwardedRemoteAddressResolver 有两个静态构造函数方法:

  • XForwardedRemoteAddressResolver::trustAll返回一个RemoteAddressResolver始终采用X-Forwarded-For标头中找到的第一个IP地址的。这种方法容易受到欺骗,因为恶意客户端可能会为设置初始值,该初始值X-Forwarded-For会被解析程序接受。
  • XForwardedRemoteAddressResolver::maxTrustedIndex采用与Spring Cloud Gateway前面运行的受信任基础结构数量相关的索引。例如,如果只能通过HAProxy访问Spring Cloud Gateway,则应使用值1。如果在访问Spring Cloud Gateway之前需要两跳可信基础架构,则应使用值2。

考虑以下标头值:

X-Forwarded-For: 0.0.0.1, 0.0.0.2, 0.0.0.3

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

maxTrustedIndexresult
[Integer.MIN_VALUE,0](invalid, IllegalArgumentException during initialization)
10.0.0.3
20.0.0.2
30.0.0.1
[4, Integer.MAX_VALUE]0.0.0.1

以下示例显示了如何使用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")
)

组合使用

server:
  port: 8080
spring:
  application:
    name: api-gateway
  cloud:
    gateway:
      routes:
        - id: gateway-service
          uri: https://www.baidu.com
          order: 0
          predicates:
            - Host=**.foo.org
            - Path=/headers
            - Method=GET
            - Header=X-Request-Id, \d+
            - Query=foo, ba.
            - Query=baz
            - Cookie=chocolate, ch.p

各种 Predicates 同时存在于同一个路由时,请求必须同时满足所有的条件才被这个路由匹配。

一个请求满足多个路由的断言条件时,请求只会被首个成功匹配的路由转发

相关源码

Spring Cloud 相关系列文章目录

网关服务

Spring Cloud Gateway


QQ群【837324215】
关注我的公众号【Java大厂面试官】,回复:常用工具资源等关键词(更多关键词,关注后注意提示信息)获取更多免费资料。

公众号也会持续输出高质量文章,和大家共同进步。

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

lakernote

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值