SpringCloud系列之网关gateway-5.断言功能详解
前面我们了解了Route的功能,这一节我们来看一下Gateway最重要的一个核心功能-断言,这个功能决定了一个HTTP请求应该由哪个Route来做路由。
Predicate机制
Predicate是Java 8中引入的一个新功能,就和我们平时在项目中写单元测试时用到的Assertion差不多,Predicate接收一个判断条件,返回一个ture或false的布尔值结果,告知调用方判断结果。你也可以通过and(与),or(或)和negative(非)三个操作符将多个Predicate串联在一块共同判断。
说白了Predicate就是一种路由规则,通过Gateway中丰富的内置断言的组合,我们就能让一个请求找到对应的Route来处理
断言的作用阶段
一个请求在抵达网关层后,首先就要进行断言匹配,在满足所有断言之后才会进入Filter阶段。有关Filter的内容将在接下来的小节内详细介绍。
常用断言介绍
Gateway提供了十多种内置断言,我们选几种常用的断言规则跟大家介绍下
路径匹配
Path断言是最常用的一个断言请求,几乎所有路由都要使用到它,我们来看一下它的例子
.route(r -> r.path("/gateway/**")
.uri("lb://FEIGN-SERVICE-PROVIDER/")
)
.route(r -> r.path("/baidu")
.uri("http://baidu.com:80/")
)
Path断言的使用非常简单,就像我们在Controller中配置@RequestPath的方式一样,在Path断言中填上一段URL匹配规则,当实际请求的URL和断言中的规则相匹配的时候,就下发到该路由中URI指定的地址,这个地址可以是一个具体的HTTP地址,也可以是Eureka中注册的服务名称。在上面的例子中,如果我们访问“/gateway/test”,这个路径将匹配到第一个路由。
Method断言
这个断言是专门验证HTTP Method的,在下面的例子中,我们把Method断言和Path断言通过一个and连接符合并起来,共同作用于路由判断,当我们访问“/gateway/sample”并且HTTP Method是GET的时候,将适配下面的路由
.route(r -> r.path("/gateway/**")
.and().method(HttpMethod.GET)
.uri("lb://FEIGN-SERVICE-PROVIDER/")
)
RequestParam匹配
请求断言也是在业务中经常使用的,它会从ServerHttpRequest中的Parameters列表中查询指定的属性,有如下两种不同的使用方式
.route(r -> r.path("/gateway/**")
.and().method(HttpMethod.GET)
.and().query("name", "test")
.and().query("age")
.uri("lb://FEIGN-SERVICE-PROVIDER/")
)
属性名验证 如
query("age")
,此时断言只会验证QueryPrameters列表中是否包含了一个叫age的属性,并不会验证它的值
属性值验证 如
query("name", "test")
,它不仅会验证name属性是否存在,还会验证它的值是不是和断言相匹配,比如当前的断言会验证请求参数中的name属性值是不是test,第二个参数实际上是一个用作模式匹配的正则表达式
Header断言
这个断言会检查Header中是否包含了响应的属性,通常可以用来验证请求是否携带了访问令牌,比如如下设置:
.route(r -> r.path("/gateway/**")
.and().header("Authorization")
.uri("lb://FEIGN-SERVICE-PROVIDER/")
)
上面的断言指定了Header中必须包含一个Authorization属性,Header断言和Query断言一样,也可以通过传入两个参数的形式对属性值进行检查
Cookie断言
顾名思义,Cookie验证的是Cookie中保存的信息,Cookie断言和上面介绍的两种断言使用方式大同小异,唯一的不同是它必须连同属性值一同验证,不能单独只验证属性是否存在,示例如下:
.route(r -> r.path("/gateway/**")
.and().cookie("name", "test")
.uri("lb://FEIGN-SERVICE-PROVIDER/")
)
时间片匹配
时间匹配有三种模式,分别是Before、After和Between,这些断言指定了在什么时间范围内路由才会生效
.route(r -> r.path("/gateway/**")
.and().before(ZonedDateTime.now().plusMinutes(1))
.uri("lb://FEIGN-SERVICE-PROVIDER/")
)
以Before断言为例,它接受的是一个ZonedDateTime参数,用来表示生效的时间。比如上面的例子中我们使用了
ZonedDateTime.now().plusMinutes(1)
表示当前时间的后一分钟,由于路由的规则是在项目启动时加载的,那么这里的当前时间也就是项目加载完成的时间,因此该路由的有效时间就是服务启动后的一分钟以内。
自定义断言
Gateway也提供了一个扩展方法,用来将自定义的断言应用到路由上