至此微服务网关系列文章已出:
- 【云原生&微服务>SCG网关篇一】为什么要有网关、生产环境如何选择网关
- 云原生&微服务>SCG网关篇二】生产上那些灰度发布方式
- 【云原生&微服务>SCG网关篇三】Spring Cloud Gateway是什么、详细使用案例
聊了以下问题:
- 为什么要有网关?网关的作用是什么?
- 网关的分类?
- 网关的技术选型?
- 使用网关时常用的灰度发布方式有哪些?
- Spring Cloud Gateway是什么?详细使用案例?
本文接着聊SpringCloudGateway内嵌的PredicateFactory如何使用;
PS:SpringCloud版本信息:
<properties>
<spring-boot.version>2.4.2spring-boot.version>
<spring-cloud.version>2020.0.1spring-cloud.version>
<spring-cloud-alibaba.version>2021.1spring-cloud-alibaba.version>
properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-dependenciesartifactId>
<version>${spring-boot.version}version>
<type>pomtype>
<scope>importscope>
dependency>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-dependenciesartifactId>
<version>${spring-cloud.version}version>
<type>pomtype>
<scope>importscope>
dependency>
<dependency>
<groupId>com.alibaba.cloudgroupId>
<artifactId>spring-cloud-alibaba-dependenciesartifactId>
<version>${spring-cloud-alibaba.version}version>
<type>pomtype>
<scope>importscope>
dependency>
dependencies>
dependencyManagement>
路由谓词工厂(Route Predicate Factories
)负责生成一些谓词条件(匹配规则),让请求过来的时候找到对应的 Route 进行处理,并且谓词工厂可以多个一起使用。
Gateway内置了很多谓词工厂,从官方文档来看,Spring Cloud Gateway内置了11种PredicateFactory:
但是我们跟到spring-cloud-gateway-server:3.0.1
项目的源代码中会发现,好像比文档中多了两个(CloudFoundryRouteServiceRoutePredicateFactory、ReadBodyRoutePredicateFactory):
不知道官方是什么用意,我们这里就先不管这多出的两个PredicateFactory;接着看Spring Cloud GateWay 内置的11种 PredicateFactory 的使用。
Route Predicate Factory支持设置一个时间或一个时间范围,在Gateway请求进行转发的时候,可以通过判断在这个时间之前、之后 或 之间决定如何转发、是否转发;
从官方文档我们可以看出在 Spring 中是通过 ZonedDateTime
来对时间进行的对比,ZonedDateTime 是 Java 8 中用于表示带时区的日期时间信息类,ZonedDateTime 支持通过时区来设置时间,中国的时区是:Asia/Shanghai。
After Route Predicate匹配在指定日期时间之后发生的请求;
server:
port: 9999
spring:
cloud:
gateway:
routes:
- id: time_before_route
uri: http://127.0.0.1:9001
predicates:
- After=2022-01-01T00:00:00.000+08:00[Asia/Shanghai]
这里表示所有在北京时间2022年1月1日 00:00:00
之后访问http://127.0.0.1:9999
地址的请求都会被路由到http://127.0.0.1:9001
地址上;
当前时间为北京时间2022-07-13 19:00:00
,把After Route Predicate的时间改为北京时间2022-07-13 21:00:00
;
server:
port: 9999
spring:
cloud:
gateway:
routes:
- id: time_before_route
uri: http://127.0.0.1:9001
predicates:
- After=2022-07-13T13:00:00.000+08:00[Asia/Shanghai]
由于当前时间还没到北京时间2022-07-13 21:00:00
,所以请求http://127.0.0.1:9999
地址的请求都会报错404,not found。
后续本文只给出符合Predicate谓语的情况,不符合的情况以此类推。
Before Route Predicate匹配在指定日期时间之前发生的请求;
server:
port: 9999
spring:
cloud:
gateway:
routes:
- id: time_after_route
uri: http://127.0.0.1:9001
predicates:
- Before=2023-01-01T00:00:00.000+08:00[Asia/Shanghai]
这里表示所有在北京时间2023年1月1日 00:00:00
之前访问http://127.0.0.1:9999
地址的请求都会被路由到http://127.0.0.1:9001
地址上;
Between Route Predicate匹配在指定日期时间范围之内发生的请求;
server:
port: 9999
spring:
cloud:
gateway:
routes:
- id: time_between_route
uri: http://127.0.0.1:9001
predicates:
- Between=2020-01-01T00:00:00.000+08:00[Asia/Shanghai], 2024-01-01T00:00:00.000+08:00[Asia/Shanghai]
这里表示所有在北京时间2020年1月1日 00:00:00
之后 在北京时间2024年1月1日 00:00:00
之前 访问http://127.0.0.1:9999
地址的请求都会被路由到http://127.0.0.1:9001
地址上;
此种方式通常对于维护时间窗口很适用,比如限时抢购
场景。
Cookie Route Predicate 会接收两个参数:Cookie name、Java的正则表达式;谓词会根据Cookie name名称 和 其值 与配置的正则表达式做匹配,匹配上则执行路由,否则404。
server:
port: 9999
spring:
cloud:
gateway:
routes:
- id: cookie_route
uri: http://127.0.0.1:9001
predicates:
- Cookie=saint, handsome
这里表示请求的Cookie中属性名为saint,属性值符合正则规则
(handsome)的 访问http://127.0.0.1:9999
地址的请求都会被路由到http://127.0.0.1:9001
地址上;
如果把Cookie中的saint=handsome
移除,则会报错404;
针对请求头Header做的路由和Cookie基本一样;
Header Route Predicate 会接收两个参数:Header name、Java的正则表达式;谓词会根据Header nam 和 其值 与配置的正则表达式做匹配,匹配上则执行路由,否则404。
server:
port: 9999
spring:
cloud:
gateway:
routes:
- id: header_route
uri: http://127.0.0.1:9001
predicates:
- Header=saint-header, \d+
这里表示请求的Header名为saint-header,属性值符合正则规则
(\d+)的 访问http://127.0.0.1:9999
地址的请求都会被路由到http://127.0.0.1:9001
地址上;
如果把saint-header属性的值修改为不是全数字的数据,则会报错404;
Host Route Predicate 接收一个参数,参数类型是一组正则表达式形式的域名列表;每一个pattern是一个 ant 分隔的模板,用.号作为分隔符;它通过参数( Host header)中的主机地址作为匹配规则。
server:
port: 9999
spring:
cloud:
gateway:
routes:
- id: host_route
uri: http://127.0.0.1:9001
predicates:
- Host=**.saint.com
这里表示请求的Header名为Host,属性值符合正则规则
(.saint.com)的 访问http://127.0.0.1:9999
地址的请求都会被路由到http://127.0.0.1:9001
地址上;
如果我们把Predicate写成**saint.com
,则正则表达式中的仅能代表不包含.
的一个字符串,如果把Host配成www.saint.com
,就会报404;
Method Route Predicate通过判断HTTP Methods(POST、GET、PUT、DELETE) 进行路由。
这里表示Method为GET、访问http://127.0.0.1:9999
地址的请求都会被路由到http://127.0.0.1:9001
地址上;
如果请求的Method不是GET,比如POST http://127.0.0.1:9999/ 会报"404 Not Found";
Path Route Predicate 接收一个匹配路径的参数来判断是否走路由。
server:
port: 9999
spring:
cloud:
gateway:
routes:
- id: path_route
uri: http://127.0.0.1:9001 #访问地址
predicates:
- Path=/hello/**
这里表示访问http://127.0.0.1:9999/hello/
地址的请求都会被路由到http://127.0.0.1:9001/hello
地址上;
如果是使用@Pathvariable注解动态构建请求,则可以写成Path=/hello/{name}
,name为动态入参
此外:Path Predicate 一般结合StripPrefix Filter使用。
server:
port: 9999
spring:
cloud:
gateway:
routes:
- id: simple_service_route
uri: http://127.0.0.1:9001
predicates:
# 路径匹配规则,向http://localhost:9999/gateway/simple-service/路径发送请求时,将会被转发到http://localhost:9001
- Path=/gateway/simple-service/**
filters:
# StripPrefix参数表示在将请求发送到下游之前从请求中剥离的路径个数。
# 如果设置StripPrefix=2,则当通过网关向/gateway/simple-service/hello发出请求时,对simple-service的请求将类似于/hello。
- StripPrefix=2
Predicate中配置的Path为/gateway/simple-service/**
,StripePrefix的值为2,当我们要通过gateway接收一个请求时,请求为:http://127.0.0.1:9999/gateway/simple-service/hello/sayHello
,则转发到http://127.0.0.1:9001
上的请求地址为:http://127.0.0.1:9001/hello/sayHello
。
Query route predicate有两个参数,一个是必填的查询属性名,一个是选填的查询属性名对应的属性值(Java正则表达式
);
server:
port: 9999
spring:
cloud:
gateway:
routes:
- id: path_route
uri: http://127.0.0.1:9001
predicates:
- Query=name
请求中包含 name 属性的参数时才会匹配路由,即:请求http://localhost:9999/**
会转发http://localhost:9001/**
。
如果请求中不包含 name 属性的参数则会报"404 Not Found";
server:
port: 9999
spring:
cloud:
gateway:
routes:
- id: path_route
uri: http://127.0.0.1:9001
predicates:
- Query=name, .*saint
请求中包含 name 属性的参数、并且name参数对应的值符合正则表达式规则(.*saint
,即以saint结尾的字符串)时才会匹配路由,即:请求http://localhost:9999/**
会转发http://localhost:9001/**
;否则会报"404 Not Found"。
RemoteAddr route predicate支持根据 ip 区间号段进行路由,其接受 cidr 符号 (IPv4 或 IPv6) 字符串的列表(最小大小为 1),例如 192.168.0.1/16 (其中 192.168.0.1 是 IP 地址,16 是子网掩码)。
server:
port: 9999
spring:
cloud:
gateway:
routes:
- id: remote_addr_route
uri: http://127.0.0.1:9001
predicates:
- RemoteAddr=192.168.1.1/24
当且仅当请求IP是192.168.1.1/24网段,例如192.168.1.10,才会路由通过。
Weight route predicate 有两个参数:权重组group 和 权重比 weight(int类型),最终权重按组计算。可以看做是一种根据权重的负载均衡。
server:
port: 9999
spring:
cloud:
gateway:
routes:
- id: weight_high
uri: http://127.0.0.1:9001
predicates:
- Weight=group1, 8
- id: weight_low
uri: http://127.0.0.1:9002
predicates:
- Weight=group1, 2
这里表示在同一个权重组(group1)下有两个路由,http://127.0.0.1:9001
链接的权重为8,http://127.0.0.1:9002
链接的权重为2;假设过来10个请求,则8个请求打到http://127.0.0.1:9001
、2个请求打到http://127.0.0.1:9002
。
多个Predicate 同时存在于同一个路由时,请求必须同时满足所有的条件才被这个路由匹配。
server:
port: 9999
spring:
cloud:
gateway:
routes:
- id: weight_high
uri: http://127.0.0.1:9001
predicates:
- After=2022-07-01T21:00:00.000+08:00[Asia/Shanghai]
- Method=GET
- Query=name
这里表示在2022年7月1日之后,参数中带有name属性的GET 类型请求可以匹配到路由。
本文我们把Spring Cloud Gateway内置的11种PredicateFactory都介绍了一下,下一篇文章我们聊一下如何自定义一个PredicateFactory。