SpringCloud 2023 Gateway的Predicate配置详解、自定义Route Predicate Factory

1. Predicate Factories介绍

Spring Cloud Gateway将路由匹配作为Spring WebFlux HandlerMapping基础架构的一部分。包含共12种内置的Route Predicate Factory,可以配置多个Route Predicate Factory,用逻辑and进行组合,如果HTTP请求的不同属性满足条件,则跳转到指定的route路由
Predicate Factories介绍

启动Spring Cloud Gateway服务时,日志会打印加载的Route Predicate Factory,如下所示。所有Route Predicate Factory的父类都是RoutePredicateFactory

2024-08-09T11:13:00.258+08:00  INFO 17080 --- [gatewayServer] [           main] o.s.c.g.r.RouteDefinitionRouteLocator    : Loaded RoutePredicateFactory [After]
2024-08-09T11:13:00.258+08:00  INFO 17080 --- [gatewayServer] [           main] o.s.c.g.r.RouteDefinitionRouteLocator    : Loaded RoutePredicateFactory [Before]
2024-08-09T11:13:00.258+08:00  INFO 17080 --- [gatewayServer] [           main] o.s.c.g.r.RouteDefinitionRouteLocator    : Loaded RoutePredicateFactory [Between]
2024-08-09T11:13:00.258+08:00  INFO 17080 --- [gatewayServer] [           main] o.s.c.g.r.RouteDefinitionRouteLocator    : Loaded RoutePredicateFactory [Cookie]
2024-08-09T11:13:00.258+08:00  INFO 17080 --- [gatewayServer] [           main] o.s.c.g.r.RouteDefinitionRouteLocator    : Loaded RoutePredicateFactory [Header]
2024-08-09T11:13:00.258+08:00  INFO 17080 --- [gatewayServer] [           main] o.s.c.g.r.RouteDefinitionRouteLocator    : Loaded RoutePredicateFactory [Host]
2024-08-09T11:13:00.258+08:00  INFO 17080 --- [gatewayServer] [           main] o.s.c.g.r.RouteDefinitionRouteLocator    : Loaded RoutePredicateFactory [Method]
2024-08-09T11:13:00.258+08:00  INFO 17080 --- [gatewayServer] [           main] o.s.c.g.r.RouteDefinitionRouteLocator    : Loaded RoutePredicateFactory [Path]
2024-08-09T11:13:00.258+08:00  INFO 17080 --- [gatewayServer] [           main] o.s.c.g.r.RouteDefinitionRouteLocator    : Loaded RoutePredicateFactory [Query]
2024-08-09T11:13:00.258+08:00  INFO 17080 --- [gatewayServer] [           main] o.s.c.g.r.RouteDefinitionRouteLocator    : Loaded RoutePredicateFactory [ReadBody]
2024-08-09T11:13:00.258+08:00  INFO 17080 --- [gatewayServer] [           main] o.s.c.g.r.RouteDefinitionRouteLocator    : Loaded RoutePredicateFactory [RemoteAddr]
2024-08-09T11:13:00.258+08:00  INFO 17080 --- [gatewayServer] [           main] o.s.c.g.r.RouteDefinitionRouteLocator    : Loaded RoutePredicateFactory [XForwardedRemoteAddr]
2024-08-09T11:13:00.258+08:00  INFO 17080 --- [gatewayServer] [           main] o.s.c.g.r.RouteDefinitionRouteLocator    : Loaded RoutePredicateFactory [Weight]
2024-08-09T11:13:00.258+08:00  INFO 17080 --- [gatewayServer] [           main] o.s.c.g.r.RouteDefinitionRouteLocator    : Loaded RoutePredicateFactory [CloudFoundryRouteService]

2. 常用的内置Route Predicate使用

2.1 配置语法说明

提供了两种配置语法:

  • 快捷语法(常用):filter名称=filter值,filter值用逗号分隔
spring:
  cloud:
    gateway:
      routes:
        - id: payRoute                  
          uri: lb://payment              
          predicates:
            - Path=/pay/**              
            - Cookie=cookieKey,cookieValue  # 需同时匹配Path和Cookie,HTTP请求的Cookie的key需要为cookieKey,value需要为cookieValue
  • 全部展开语法
spring:
  cloud:
    gateway:
      routes:
        - id: payRoute                  
          uri: lb://payment              
          predicates:
            - Path=/pay/**              
            - name: Cookie  # 需同时匹配Path和Cookie,HTTP请求的Cookie的key需要为cookieKey,value需要为cookieValue
              args:
                name: cookieKey
                regexp: cookieValue

2.2 配置使用

  • After Route Predicate: 在指定时间之后发送的HTTP请求才符合要求。常用于秒杀、抢购。时间参数值可以通过System.out.println(ZonedDateTime.now())
    • 配置: - After=2024-08-09T13:28:40.332233100+08:00[Asia/Shanghai]
    • 效果: 在13:27分的时候向网关http://localhost:8088/pay/get/1发送请求报404,在13:29分的时候向网关发送请求成功
  • Before Route Predicate: 在指定时间之前发送的HTTP请求才符合要求。时间参数值可以通过System.out.println(ZonedDateTime.now())
    • 配置: - Before=2024-08-09T13:32:40.332233100+08:00[Asia/Shanghai]
    • 效果: 在13:31分的时候向网关发送请求成功,在13:33分的时候向网关http://localhost:8088/pay/get/1发送请求报404
  • Between Route Predicate: 在指定时间之间发送的HTTP请求才符合要求。时间参数值可以通过System.out.println(ZonedDateTime.now())
    • 配置: - Between=2024-08-09T13:33:40.332233100+08:00[Asia/Shanghai],2024-08-09T13:36:40.332233100+08:00[Asia/Shanghai]
    • 效果: 在13:32分的时候向网关http://localhost:8088/pay/get/1发送请求报404,在13:35分的时候向网关发送请求成功,在13:37分的时候向网关http://localhost:8088/pay/get/1发送请求报404
  • Cookie Route Predicate: 需要两个参数,一个是Cookie name ,一个是正则表达式。路由规则会通过获取对应的Cookie name值和正则表达式去匹配,如果匹配上就会执行路由,如果没有匹配上则不执行
    • 配置: - Cookie=username,lily
    • 效果:执行curl http://localhost:8088/pay/get/1向网关发送请求报404,执行curl http://localhost:8088/pay/get/1 --cookie "username=lily"向网关发送请求成功
  • Header Route Predicate: 需要两个参数,一个是属性名称 ,一个是正则表达式。路由规则会通过获取对应的Header的属性名称和正则表达式去匹配,如果匹配上就会执行路由,如果没有匹配上则不执行
    • 配置: - Header=requestId, \d+。说明:请求头要有requestId属性, 并且值为整数的正则表达式
    • 效果:执行curl http://localhost:8088/pay/get/1向网关发送请求报404,执行curl http://localhost:8088/pay/get/1 -H "requestId:123456"向网关发送请求成功
  • Host Route Predicate: 接收一组参数,即一组匹配的域名列表,域名是Ant风格模式的,用逗号分隔。路由规则会通过获取对应的Header的Host的值去匹配,如果匹配上任意一个域名就会执行路由,如果没有匹配上则不执行
    • 配置: - Host=**.h1.com,**.h2.com。说明:请求头的Host匹配任意域名都可以
    • 效果:执行curl http://localhost:8088/pay/get/1 -H "Host:nb.h0.com"向网关发送请求报404,执行curl http://localhost:8088/pay/get/1 -H "Host:nb.h1.com"向网关发送请求成功,执行curl http://localhost:8088/pay/get/1 -H "Host:nb.h2.com"向网关发送请求成功
  • Path Route Predicate: 接收一组参数,即一组匹配的路径列表,路径是Ant风格模式的,用逗号分隔。路由规则会通过获取对应的path路径的值去匹配,如果匹配上任意一个路径就会执行路由,如果没有匹配上则不执行
    • 配置: - Path=/pay/get/{segment},/pay/list/**
    • 效果:向网关发送http://localhost:8088/pay/get2/1请求报404,向网关发送http://localhost:8088/pay/get/1请求成功,向网关发送http://localhost:8088/pay/list/detail/1请求成功
  • Query Route Predicate: 需要两个参数,一个是请求参数名称 ,一个是正则表达式。路由规则会通过获取对应的请求参数的名称和正则表达式去匹配,如果匹配上就会执行路由,如果没有匹配上则不执行
    • 配置: - Query=username, \d+。说明:请求参数要有username名称, 并且其值为整数的正则表达式
    • 效果:执行curl http://localhost:8088/pay/get/1向网关发送请求报404,执行curl http://localhost:8088/pay/get/1?username=123456"向网关发送请求成功
  • RemoteAddr Route Predicate: 接收一组参数,即一组匹配的远程地址列表,远程地址是CIDR(无类域间路由),用逗号分隔。路由规则会通过获取对应的远程地址的值去匹配,如果匹配上任意一个远程地址就会执行路由,如果没有匹配上则不执行
    • CIDR(无类域间路由):支持IPV4和IPV6, 一个形如255.255.255.255的ip地址共32位。72.108.25.1/24无类域间路由表示前24位是网络地址,则只有8位是主机地址,所以主机范围为72.108.25.072.108.25.25572.109.25.2/30无类域间路由表示前30位是网络地址,则只有2位是主机地址,所以主机范围为72.109.25.072.109.25.3
    • 配置: - RemoteAddr=72.108.25.1/24,72.109.25.2/30
    • 效果:从ip为72.107.25.8的服务器向网关发送http://10.8.12.67:8088/pay/get/1请求报404,从ip为72.108.25.18的服务器向网关发送http://10.8.12.67:8088/pay/get/1请求成功,从ip为72.109.25.3的服务器向网关发送http://10.8.12.67:8088/pay/get/1请求成功
  • Method Route Predicate: 接收一组参数,即一组匹配的请求方式列表,用逗号分隔。路由规则会通过获取对应的请求方式的值去匹配,如果匹配上任意一个请求方式就会执行路由,如果没有匹配上则不执行
    • 配置: - Method=GET,POST
    • 效果:以PUT方式向网关发送http://10.8.12.67:8088/pay/get/1请求报404,以GET方式向网关发送http://10.8.12.67:8088/pay/get/1请求成功,以POST方式向网关发送http://10.8.12.67:8088/pay/get/1请求成功

3. 自定义Route Predicate Factory

3.1 实现步骤:

  1. 在gatewayServer项目中新建自定义Predicate Factory类MyRoutePredicateFactory。类名的后缀必须是RoutePredicateFactory。所以这里创建的是一个My Route Predicate
  2. 类继承AbstractRoutePredicateFactory。也可以继承RoutePredicateFactory接口
  3. 实现无参构造器,调用父类的构造器
  4. 实现一个配置类MyRoutePredicateFactory.Config,定义需要验证的值userType
  5. 重写父类的apply方法,实现匹配userType成功和失败的逻辑
  6. 重写父类的shortcutFieldOrder方法,让其支持shortcut语法

3.2 实现代码如下:

import jakarta.validation.constraints.NotEmpty;
import lombok.Getter;
import lombok.Setter;
import org.springframework.cloud.gateway.handler.predicate.AbstractRoutePredicateFactory;
import org.springframework.stereotype.Component;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.server.ServerWebExchange;

import java.util.Collections;
import java.util.List;
import java.util.function.Predicate;


@Component
public class MyRoutePredicateFactory extends AbstractRoutePredicateFactory<MyRoutePredicateFactory.Config>
{

    public MyRoutePredicateFactory()
    {
        super(MyRoutePredicateFactory.Config.class);
    }

    @Validated  // 用@validated来校验数据,如果数据异常会统一抛出异常
    public static class Config {   
        @Setter
        @Getter
        @NotEmpty
        private String userType;     // 验证用户类型
    }

    @Override
    public Predicate<ServerWebExchange> apply(MyRoutePredicateFactory.Config config)
    {
        return new Predicate<ServerWebExchange>()
        {
            @Override
            public boolean test(ServerWebExchange serverWebExchange)
            {
                // 获取request参数中的userType
                String userType = serverWebExchange.getRequest().getQueryParams().getFirst("userType");

                if (userType == null) return false;

                // 如果request参数中的userType的值,和gatewayServer配置文件中配置的值相等,则符合条件
                if(userType.equals(config.getUserType())) return true;
               
                return false;
            }
        };
    }


    @Override
    public List<String> shortcutFieldOrder() {
        // 列表: [userType]
        return Collections.singletonList("userType");
    }

}

3.3 application.yml配置

全部展开语法配置如下:

            - name: My
              args:
                userType: gold

快捷语法配置: - My=gold

3.4 测试

启动gatewayServer项目,会打印如下日志,表示加载My Route Predicate成功

2024-08-09T17:58:37.861+08:00  INFO 5220 --- [gatewayServer] [           main] o.s.c.g.r.RouteDefinitionRouteLocator    : Loaded RoutePredicateFactory [My]

向网关发送http://localhost:8088/pay/get/1请求报404,向网关发送http://localhost:8088/pay/get/1?userType=gold请求成功

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值