微服务架构-服务网关(Gateway)-断言功能详解

断言功能详解(Predict)

前面我们了解了Route的功能,这一节我们来看一下Gateway最重要的一个核心功能-断言,这个功能决定了一个HTTP请求应该由哪个Route来做路由。

1、Predicate机制

Predicate 是Java 8中引入的一个新功能,就和我们平时在项目中写单元测试时用到的Assertion差不多,Predicate 接收一个判断条件,返回一个 ture 或 false 的布尔值结果,告知调用方判断结果。你也可以通过and (与),or(或)和negative(非) 三个操作符将多Predicate 串联在一块共同判断。

前面说到Gateway是挡在微服务前面的街达室大爷,那这Predicate 就是和大答的接头暗号。比如大爷可以要求你的Request中必须带有某个指定的参数叫name。对应的值必须是一个指定的人名“马冬梅”,如果你的Request中没有包含name,或者对应的人名给成了“马北梅”,那就是断言失败,只有当你的请求完全和接头暗号匹配的时候,大爷才能给你放行。

说白了Predicate就是一种路由规则,通过Gateway中丰富的内置断言的组合,我们就能让一个请求找到对应的Route来处理。

1.1)断言的作用阶段

一个请求在抵达网关层后,首先就要进行断言匹配,在满足所有断言之后才会进入Filter阶段,有关Fiter的内容将在接下来的小节内详细介绍。

2、常用断言介绍

Gateway提供了十多种内置断言,我们选几种常用的断言规则跟大家介绍下:

2.1)路径匹配

Path断言是最常用的一个断言请求,几乎所有路由都要便用到它,我们来看一下它的例子:

.route(r -> r.path("/gateway/**")
             .uri("lb://FEIGN-SERVICE-PROVIDER/")
)
.route(r -> r.path("/baidu")
             .uri("http://baidu.com:80/")
)

Path断言的使用非常简单,就像我们在Controller中配置@RequestPah的方式一样,在Path断言中填上一段URL匹配规则,当实际请求的URL和断言中的规则相匹配的时候,就下发到该路由中URL指定的地址,这个地址可以是一个具体的HTTP地址,也可以是Eureka中注册的服务名称。在上面的例子中,如果我们访问 “/gateway/test”,这个路径将匹配到第一个路由。

2.2)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/")
)

2.3)RequestParam匹配

请求断言也是在业务中经常使用的,它会从ServerHttpReques中的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,第二个参数实际上是一个用作模式匹配的正则表达式。

2.4)Header断言

这个断言会检查Header中是否包含了响应的属性,通常可以用来验证请求是否携带了访问令牌,比如如下设置:

.route(r -> r.path("/gateway/**")
             .and().header("Authorization")
             .uri("lb://FEIGN-SERVICE-PROVIDER/")
)

上面的断言指定了Header中必须包含一个Authorization属性,Header断言和Query 断言一样,也可以通过传入两个参数的形式对属性值进行检查。

2.5)Cookie断言

顾名思义,Cookie验证的是Cookie中保存的信息,Cookie断言和上面介绍的两种断言使用方式大同小异,唯一的不同是它必须同属性值一同验证,不能单独只验证属性是否存在,示例如下:

.route(r -> r.path("/gateway/**")
             .and().cookie("name", "test")
             .uri("lb://FEIGN-SERVICE-PROVIDER/")
)

2.6)时间片匹配

时间匹配有三种模式,分别是Before、After和Between,这些断言指定了在什么时间范围内路由才会生效

.route(r -> r.path("/gateway/**")
             .and().before(ZonedDateTime.now().plusMinutes(1))
             .uri("lb://FEIGN-SERVICE-PROVIDER/")
)

以Before断言为例,它接受的是一个ZonedDateTime参数,用来表示生效的时间。比如上面的例子中我们使用了 ZonedDateTime,now(),plusinutes(1) 表示当前时间的后一分钟,由于路由的规则是在项目启动时加载的,那么这里的当前时间也就是项目加载完成的时间,因此该路由的有效时间就是服务启动后的一分钟以内。

3、自定义断言

GateWay也提供了一个扩展方法,用来将自定义的断言应用到路由上,实现一个自定义断言,完成个小功能:将所有请求参数大于5个的访问请求拦截掉,即ReguestParam个数小于5个的请求才能被放行。

  • 提示1: 所有断言类都可以继承自AbstractRoutePredicateFactory;
  • 提示2: 在路由配置时可以通过 predicate 或者 asyncPredicate传入一个自定义断言。

你可能感兴趣的:(微服务架构,架构,微服务,gateway)