【云原生&微服务>SCG网关篇四】Spring Cloud Gateway内置的11种PredicateFactory如何使用

一、前言

至此微服务网关系列文章已出:

  1. 【云原生&微服务>SCG网关篇一】为什么要有网关、生产环境如何选择网关
  2. 云原生&微服务>SCG网关篇二】生产上那些灰度发布方式
  3. 【云原生&微服务>SCG网关篇三】Spring Cloud Gateway是什么、详细使用案例

聊了以下问题:

  1. 为什么要有网关?网关的作用是什么?
  2. 网关的分类?
  3. 网关的技术选型?
  4. 使用网关时常用的灰度发布方式有哪些?
  5. Spring Cloud Gateway是什么?详细使用案例?

本文接着聊SpringCloudGateway内嵌的PredicateFactory如何使用;

PS:SpringCloud版本信息:

<properties>
    <spring-boot.version>2.4.2</spring-boot.version>
    <spring-cloud.version>2020.0.1</spring-cloud.version>
    <spring-cloud-alibaba.version>2021.1</spring-cloud-alibaba.version>
</properties>

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-dependencies</artifactId>
            <version>${spring-boot.version}</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
        <!--整合spring cloud-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-dependencies</artifactId>
            <version>${spring-cloud.version}</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
        <!--整合spring cloud alibaba-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-alibaba-dependencies</artifactId>
            <version>${spring-cloud-alibaba.version}</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

二、PredicateFactory(Route Predicate Factories)

路由谓词工厂(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 的使用。

1、时间相关

Route Predicate Factory支持设置一个时间或一个时间范围,在Gateway请求进行转发的时候,可以通过判断在这个时间之前、之后 或 之间决定如何转发、是否转发;

在这里插入图片描述

从官方文档我们可以看出在 Spring 中是通过 ZonedDateTime 来对时间进行的对比,ZonedDateTime 是 Java 8 中用于表示带时区的日期时间信息类,ZonedDateTime 支持通过时区来设置时间,中国的时区是:Asia/Shanghai。

1)AfterRoutePredicateFactory

After Route Predicate匹配在指定日期时间之后发生的请求;

1> 匹配谓语时

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地址上;

在这里插入图片描述

2> 不匹配谓语时

当前时间为北京时间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谓语的情况,不符合的情况以此类推。

2)BeforeRoutePredicateFactory

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地址上;

3)BetweenRoutePredicateFactory

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地址上;

此种方式通常对于维护时间窗口很适用,比如限时抢购场景。

2、Cookie相关(CookieRoutePredicateFactory)

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;

在这里插入图片描述

3、Header相关(HeaderRoutePredicateFactory)

针对请求头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;

在这里插入图片描述

4、Host相关(HostRoutePredicateFactory)

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;

在这里插入图片描述

5、Method相关(MethodRoutePredicateFactory)

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";

在这里插入图片描述

6、Path相关(PathRoutePredicateFactory)

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为动态入参

StripePrefix Filter

此外: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

7、Query相关(QueryRoutePredicateFactory)

Query route predicate有两个参数,一个是必填的查询属性名,一个是选填的查询属性名对应的属性值(Java正则表达式);

1)仅匹配查询属性名

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";

2)匹配查询属性名和属性名对应的值

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"。

8、请求IP地址相关(RemoteAddrRoutePredicateFactory)

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,才会路由通过。

9、负载权重相关(WeightRoutePredicateFactory)

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

10、组合使用

多个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。

猜你喜欢

转载自blog.csdn.net/Saintmm/article/details/125767910