💨 作者:
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的条件,就使用该路由的配置,否则就不予处理。(可以多种路由谓词工厂自由搭配很全面)
全部内置(11种
)的路由谓词工厂:
路由谓词工厂 | Http协议匹配字段 | 备注 |
---|---|---|
After | 请求时间 | 不常用 |
Before | 请求时间 | 不常用 |
Between | 请求时间 | 不常用 |
Cookie | Cookie | 常用 |
Header | Header | 常用 |
Host | Host | 不常用 |
Method | Method | 不常用 |
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
路由谓词工厂有两个参数,datetime1
和datetime2
都是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
路由谓词工厂采用两个参数,cookiename
和regexp
(其是Java正则表达式)。该谓词匹配具有给定名称且其值与正则表达式匹配的cookie。以下示例配置cookie路由谓词工厂:
spring:
cloud:
gateway:
routes:
- id: cookie_route
uri: https://example.org
predicates:
- Cookie=somecookie, ch.p
此路由匹配具有Cookie的请求,该Cookie的名称chocolate
与ch.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.org
或beta.somehost.org
或www.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
如果请求方法是GET
或POST
,则此路由匹配。
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.
正则,所以green
和greet
都将匹配。
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
路由谓词工厂有两个参数:group
和weight
(一个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来定制解析远程地址的方式RemoteAddressResolver
Spring 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
值产生以下远程地址:
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实现相同的配置:
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大厂面试官】,回复:常用工具、资源等关键词(更多关键词,关注后注意提示信息)获取更多免费资料。
公众号也会持续输出高质量文章,和大家共同进步。