前言
本章节将介绍yml中 predicate中都可以配置哪些内容
下面所有的例子中,最终都要通过gateway路由到(跳转到)下面这个服务的ping接口
The After Route Predicate Factory
意思就是在predicate中配置一个叫做after的参数,直接先上图,然后讲解
spring:
cloud:
gateway:
routes:
- id: order-route
uri: http://localhost:8001
predicates:
- After=2017-01-20T17:42:47.789-07:00[America/Denver]
filters:
- StripPrefix=1
#StripPrefix会将url如/api/order/ping中的/api去掉后跟-path的值匹配,如果不想去掉/api就把这个去掉就行
作用:只有你当前发起的请求的时间在这个after属性设置的时间之后,才能将请求路由到uri设置的地址上。看下面例子:
我当前gateway服务的实在localhost:9001上,gateway配置如下
我要请求的内容实在localhost:8001上,如下:
假设我当前发送请求的时间是2022-07-07 14:45,根据上面的配置,我当前的时间实在after设置的之后,是满足这个设置的,所以当我起如下请求时localhost:9001/api/order/ping时,gateway会拦截到这个请求,然后检查他的请求时间满足我们after的设置,然后就会把这个请求路由到(转发到)localhost:8001/order/ping(为什么会变成这个url参考前面内容,不是这章的内容),然后就会得到一个pong的值。
但是如果我们现在把after属性的时间改成2024年(当前时间时2022年)如下:
当前发送请求的时间时2016年,那么他就不满足after设置,这是gateway就会报错,如下:
这就是after的作用。
The before Route Predicate Factory
spring:
cloud:
gateway:
routes:
- id: order-route
uri: http://localhost:8001
predicates:
- Before=2017-01-20T17:42:47.789-07:00[America/Denver]
filters:
- StripPrefix=1
before与after作用相同,只不过判断的条件不同,after是请求时间在after设置的时间之后就true,而before是请求的时间在before设置的时间之前才为true。例子我就不写了,参考after就行
The Between Route Predicate Factory
spring:
cloud:
gateway:
routes:
- id: order-route
uri: http://localhost:8001
predicates:
- Between=2017-01-20T17:42:47.789-07:00[America/Denver], 2017-01-21T17:42:47.789-07:00[America/Denver]
作用:只有当前请求的时间在between设置的时间之间时,表示才会路由(转发)到uri对应的地址上。具体根after和before相同,就不再举例
The Cookie Route Predicate Factory
spring:
cloud:
gateway:
routes:
- id: order-route
uri: http://localhost:8001
predicates:
- Cookie=chocolate, ch.p
作用:只有当前请求中中含有一个name为chocolate,他的值为ch.p的cookie时,表示才会路由(转发)到uri对应的地址上。
例子:
因为请求中设置了cookie,与yml中设置的对应,所以请求成功了,否则请求失败。
The Headers Route Predicate Factory
spring:
cloud:
gateway:
routes:
- id: order-route
uri: http://localhost:8001
predicates:
- Header=X-Request-Id, \d+
#Hearder中必须包含一个X-Request-Id的字段,他的值必须满足这个正则表达式
作用:只有当前请求中中含有一个名为X-Request-Id,他的值为数字开头header时,表示才会路由(转发)到uri对应的地址上。
看例子:
当header中含有X-Requet-Id,并且其值为数字时(满足了yml中正则表达式),就可以成功请求。否则报错404。
The host Route Predicate Factory
spring:
cloud:
gateway:
routes:
- id: order-route
uri: http://localhost:8001
predicates:
- Host=**.somehost.org,**.anotherhost.org
#header中的host的值必须满足这个正则表达式
作用:只有当前请求的header中包含一个host属性时,并且host的值满足上面的设置时,才会路由(转发)到uri对应的地址上。
例子:
虽然我的请求的地址时localhost,但是只要我的header中的host属性满足yml中host的规则就可以请求成功,否则会报404错误。
The Method Route Predicate Factory
spring:
cloud:
gateway:
routes:
- id: order-route
uri: http://localhost:8001
predicates:
- Method=GET,POST #只有当前时get或者post请求才行
作用:请求有四种方法get,post,put,delete,只有当前请求你用的方法与yml中-Method设置的相匹配时,才会路由(转发)到uri对应的地址上。
例子:
当使用的方法与yml中的Method的配置(get,post)不匹配时,请求就失败了。只有请求时我把红框里改为get或者post请求才会成功
The Path Route Predicate Factory
这个是最常用的一个,先看配置
spring:
cloud:
gateway:
routes:
- id: order-route
uri: http://localhost:8001
predicates:
- Path=/api/order/** #请求地址出去ip:端口后其他部分与这个匹配才行
作用:当请求除去ip地址:端口这部分后,剩余的部分(也成为path部分)与我们yml设置的Path匹配时,才会路由(转发)到uri对应的地址上。
例子:
我的请求中path部分与yml中path的设置匹配,所以请求就会成功访问
另外i,我们还可以这样写:
predicates:
- Path=/red/{segment},/blue/{segment}
这个{segment}表示一种路径变量,比如当你的请求path时/red/1,或者/red/a时,那么我们在GatewayFilter类中就可以通过代码获取到这个1,和a,如下:
Map<String, String> uriVariables = ServerWebExchangeUtils.getPathPredicateVariables(exchange);
String segment = uriVariables.get("segment");
The Query Route Predicate Factory
所谓Query指的就是我们请求中的请求参数。先看yml
spring:
cloud:
gateway:
routes:
- id: order-route
uri: http://localhost:8001
predicates:
- Query=id #值也可以写多个,用逗号隔开,另外这个值还可以使用正则表达式
作用:我们的请求中必须带有query指定的内容,请求才能匹配成功,才会路由(转发)到uri对应的地址上。
例子:
一定要注意:-Query=value1,value2,这样配置时是一个并列关系,也就是请求中必须同时含有这个两个参数才行。
The RemoteAddress Route Predicate Factory
意思指定客户端也就是发起请求的电脑的ip地址必须是我yml中配置的ip才行
spring:
cloud:
gateway:
routes:
- id: order-route
uri: http://localhost:8001
predicates:
- RemoteAddr=192.168.1.104 #还可以使用192.168.1.104/24的形式,24是掩码位数
作用:发起请求的电脑的ip地址必须是-RemoteAddr指定的,请求才能匹配成功,才会路由(转发)到uri对应的地址上。
例子:
我的局域网ip是192.168.1.104,与yml配置匹配,所以就成功了。
注意:请求时不能用localhost或者127.0.0.1,这样都是无效的,这样会导致服务端判断来源的时候取得的网卡地址为0.0.0.0。一定要写自己的ip地址
The Weight Route Predicate Factory
意思就是通过权重的方式指定路由到uri的比例。使用weight时,它要包含2个参数,一个是group,一个是weight的值,如下配置中group1就是参数1的group,8和2就是参数2的weight。
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
比如这个配置,就是说10次请求的话,8次将请求到https//weighthigh.org这个uri中的接口,2次将请求到https//weightlow.org这个uri中的接口.因为本人就一台机器,就不做例子了。
Modifying the Way Remote Addresses Are Resolved
一般来说我们都直接接受客户端发来的请求,但是有的时候,我们会在gateway服务前面加上一个类似于nginx这样的代理服务器,这是如果我们在yml中使用-RemoteAddr来配置时就有问题了。因为这是请求进来的所有地址都似乎代理服务器的地址,不是客户端(真正发请求的人)的地址,所以就用到这里方案RemoteAddressResolver,其原理就是通过解析请求的header中的 X-Forwarded-For,如果不懂这个名字,可以去百度。
这里说一下请求中的header中写X-Forwarded-For的格式:
X-Forwarded-For 请求头格式非常简单,就这样:
X-Forwarded-For: client, proxy1, proxy2
可以看到,XFF 的内容由「英文逗号 + 空格」隔开的多个部分组成,最开始的是离服务端最远的设备 IP,然后是每一级代理设备的 IP。
如果一个 HTTP 请求到达服务器之前,经过了三个代理 Proxy1、Proxy2、Proxy3,IP 分别为 IP1、IP2、IP3,用户真实 IP 为 IP0,那么按照 XFF 标准,服务端最终会收到以下信息:
X-Forwarded-For: IP0, IP1, IP2
例子 :这个的配置较为麻烦,仔细看
首先因为要使用RemoteAddressResolver(这是个接口),我们要先把他的实现类放到容器中,所以先做一下配置:
//这段代码放到启动类中也行,过着自己放在一个有@Configuration注解的类中也行
RemoteAddressResolver resolver = XForwardedRemoteAddressResolver.maxTrustedIndex(3);
//这个ip就好比在yml中-RemoteAddr设置的ip作用一样【1】
private static final String [] remoteAddr={ "192.168.1.104"};
@Bean
public RouteLocator routeLocator(RouteLocatorBuilder builder) {
return builder.routes().route("order_route",
r -> r.path("/api/order/ping")
.and().remoteAddr(resolver,remoteAddr)
.filters(f-> f.stripPrefix(1))
.uri("http://localhost:8001"))
.build();
}
要使用RemoteAddresszReslover的话就要使用代码方式,不能通过yml方式,所以这里配置router的就不要在yml配置了,其他的router可以在yml中配置,最后会合并二者。
然后,我们通过postman发起请求如下:
我们看到请求成功了。
下面我说一下过程:
XForwardedRemoteAddressResolver会解析postman中
然后会把这三个值的顺序进行一个反转放在一个数组为[0.0.0.3,0.0.0.2,192.168.1.104],
然后我们maxTrustedIndex(3)实际会指向数组的第三个值也就是192.168.1.104,然后拿着这个值根变量remoteAddr的值比较,如果相同说明匹配成功,就可以转发到localhost:8001/order/ping,就请求成功了。
关于这个以下几个点需要明白:
1.在header中X-Forwardared-For的书写规则(上面写了)。
2.代码中api的maxTrustedIndex(index)这个index是对应的X-Forwarded-For右侧的第几个(从1开始),至于原因在上面原理说过。
官网中的图就是上面那段原理的意思