本文将对Spring Cloud GateWay 中的 Predicate 和 Filter进行讲解,因为它们是GateWay中最重要的核心功能。可以说是网关的左膀右臂。
Predicate 和 Filter 是 Spring Cloud Gateway 的核心,通过这两个功能点的灵活配置使用,Spring Cloud Gateway 的使用变得高效、简单。Predicate 的核心作用是路由选择,通过一些列的规则配置,让我们知道哪些请求可以被某个规则转发;Filter 是过滤器,在 Predicate 删选出某些请求需要转发时,Filter 负责在这些请求的执行前或者执行后做一些处理,比如安全校验、参数处理等。
Predicate是用来请求需要处理,而Filter就是对请求需要处理做一些变更。
Predicate 是来自于JDK 8中对一个函数,Predicate接受一个输出参数,它返回对一个布尔值,可以用于接口参数的校验,判断新老数据的变化需要进行更新操作。
在 Spring Cloud Gateway 中 Spring 利用 Predicate 的特性实现了各种路由匹配规则,有通过 Header、请求参数等不同的条件来进行作为条件匹配到对应的路由。Spring Cloud Gateway 中内置了几种 Predicate 的实现,如下图:
Predicate 支持设置一个时间,在请求进行转发的时候,可以通过判断在这个时间之前或者之后进行转发。比如我们现在设置只有在2019年1月1日才会转发到我的网站,在这之前不进行转发,我就可以这样配置:
spring:
cloud:
gateway:
routes:
- id: time_route
uri: https://blog.csdn.net/qwe86314
predicates:
- After=2019-09-13T17:33:06+08:00[Asia/Shanghai]
Spring 是通过 ZonedDateTime 来对时间进行的对比,ZonedDateTime 是 Java 8 中日期时间功能里,用于表示带时区的日期与时间信息的类,ZonedDateTime 支持通过时区来设置时间,中国的时区是:Asia/Shanghai。
After Route Predicate 是指在这个时间之后的请求都转发到目标地址。上面的示例是指,请求时间在 2019年9月13日17点33分6秒之后的所有请求都转发到地https://blog.csdn.net/qwe86314
。+08:00 是指时间和 UTC 时间相差八个小时,时间地区为Asia/Shanghai
。
添加完路由规则之后,访问地址http://localhost:8080
会自动转发到https://blog.csdn.net/qwe86314
其它的两个时间判断和上面类似,只需要替换对应的 predicates 值即可。
predicates:
- After=2019-09-13T17:33:06+08:00[Asia/Shanghai]
- Before=2019-09-13T17:33:06+08:00[Asia/Shanghai]
- Between=2019-09-13T17:33:06+08:00[Asia/Shanghai], 2019-09-13T17:34:06+08:00[Asia/Shanghai]
请求方式即使页面表单的请求类型,比如:POST、GET、PUT、DELETE ,Spring Cloud Gateway 内置了 Predicate 可根据不同的请求方式来选择路由。
我们来配置这个GET方式转发:
spring:
cloud:
gateway:
routes:
- id: method_route
uri: https://blog.csdn.net/qwe86314
predicates:
- Method=GET
配置完成后我们启动项目可以通过curl 命令 如: curl http://localhost:8080
当然你也可以通过这个浏览器输入地址去访问,但是特别注意的是我们这个当前的路由只能是GET,如果尝试用POST去访问,那么返回的结果就是404。
其它的请求方式只需要将Method里面的GET换成POST、PUT等其它方式就可以来。
Path Route Predicate 接收一个匹配路径的参数来判断是否走路由。
我们来配置一下路由匹配:
spring:
cloud:
gateway:
routes:
- id: path_route
uri: http://cxytiandi.com
predicates:
- Path=/course/{segment}
当我们在浏览器地址输入http://localhost:8080/course/25
就会返回相应的页面信息,而我们输入http://localhost:8080/course/100
就会返回404的页面。
Query Route Predicate 支持传入两个参数,一个是属性名一个为属性值,属性值可以是正则表达式。
spring:
cloud:
gateway:
routes:
- id: query_route
uri: http://cxytiandi.com
predicates:
- Query=course/vipType
我们去浏览器访问:http://localhost:8080/course/vipType?=1
还可以将 Query 的值以键值对的方式进行配置,这样在请求过来时会对属性值和正则进行匹配,匹配上才会走路由。
我们将 - Query=course/vipType 修改为 - Query=course/vipType,1
这样当请求中包含course/vipType并且属性值为1就会匹配到内容否则会出404,有些网站会出现跨域问题。建议在自己网站测试。
在我们日常工作中,往往会使用多个 Predicate 来进行判断,Spring Cloud Gateway 支持同时配置多个 Predicate 条件,各种 Predicates 同时存在于同一个路由时,请求必须同时满足所有的条件才被这个路由匹配。
spring:
cloud:
gateway:
routes:
- id: mehtod_path_time
uri: http://cxytiandi.com/course
predicates:
- Method=GET
- Query=vipType,1
- After=2019-09-14T10:16:13+08:00[Asia/Shanghai]
需要注意的是:一个请求满足多个路由条件时,请求只会被首个成功匹配的路由转发
Spring Cloud Gateway 的 Filter 的生命周期不像 Zuul 的那么丰富,它只有两个:pre
和 post
。
Spring Cloud Gateway 的 Filter 分为两种:GatewayFilter 与 GlobalFilter。GlobalFilter 会应用到所有的路由上,而 GatewayFilter 将应用到单个路由或者一个分组的路由上。
GateWay Filter
Spring Cloud Gateway 内置了 25 种 GatewayFilter 和一个 Default Filters。按照不同作用方式我们将它划分为 12 大类。
Global Filter
Spring Cloud Gateway 内置了7种 GlobalFilter,比如 Netty Routing Filter、LoadBalancerClient Filter、Websocket Routing Filter 等,根据名字即可看出这些 Filter 的作用。
多个 Global Filter 可以通过 @Order 或者 getOrder() 方法指定每个 Global Filter 的执行顺序,order 值越小,Global Filter 执行的优先级越高。
利用 GatewayFilter 可以修改 Http 的请求或者响应,或者根据请求或者响应做一些特殊的限制,更多时候我们会利用 GatewayFilter 做一些具体的路由配置,接下来我们通过示例来学习。
AddRequestHeader GatewayFilter
AddRequestHeader GatewayFilter 是匹配的请求中添加Header头相关的参数。
我们首先创建一个普通的maven项目,然后再依次的在这个父模块下创建子模块:eureka、provider、consumer、gateway模块。然后分别注册到eureka。由于步骤很简单创建的过程我就不再阐述了。
spring:
application:
name: gateway
cloud:
gateway:
discovery:
locator:
enabled: true
routes:
- id: add_request_parameter_route
uri: lb://consumer
filters:
- AddRequestHeader=Content-Type, application/json
predicates:
- Method=POST
server:
port: 8083
eureka:
client:
service-url:
defaultZone: http://localhost:8888/eureka/
logging:
level:
org.springframework.cloud.gateway: debug
上面关键配置解释:
spring.cloud.gateway.discovery.locator.enabled
,是否与服务发现组件进行结合,通过 serviceId 转发到具体的服务实例。默认为 false,设为 true 便开启通过服务中心的自动根据 serviceId 创建路由的功能。spring.cloud.gateway.routes.uri=lb://consumer
,配置路由转发到名为 provider 的服务消费者。spring.cloud.gateway.routes.filters
,配置需要执行 Filter 的具体实现。spring.cloud.gateway.routes.filters.AddRequestHeader
配置请求需要的Header头spring.cloud.gateway.routes.predicates
,请求的删选条件, Filter 需要和 Predicate 配合使用。配置完成后我们分别启动,然后通过postman或者RestletClient Http请求工具然后访问http://localhost:8083/rest/SaveUser
然后加入Content-Type为application/json 然后添加参数然后发送,就返回了正确的结果如下:
注意这里默认使用了全局过滤器 LoadBalancerClient ,当路由配置中 uri 所用的协议为 lb 时(已uri: lb://provider
为例),gateway 将使用 LoadBalancerClient 把 consumer 通过 eureka 解析为实际的主机和端口,并进行负载均衡。
其它的 GatewayFilter 使用方式和上述方式比较类似,这里不再一一列举,使用时按照要求的语法配置即可。
Spring Cloud Gateway 有非常强大的 Predicate 选择机制,内置的 Predicates 实现已经满足了我们绝大部分工作场景。同时 Spring Cloud Gateway 也提供了请求过程中的各种 Filters ,其中 Filter 又区分为 GatewayFilter 和 GlobalFilter,GatewayFilter 作用于特定请求,GlobalFilter 作用于全局,实际工作中我们根据需求来选择使用。
github