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

目录

  • [1. Predicate Factories介绍](#1. Predicate Factories介绍)
  • [2. 常用的内置Route Predicate使用](#2. 常用的内置Route Predicate使用)
    • [2.1 配置语法说明](#2.1 配置语法说明)
    • [2.2 配置使用](#2.2 配置使用)
  • [3. 自定义Route Predicate Factory](#3. 自定义Route Predicate Factory)
    • [3.1 实现步骤:](#3.1 实现步骤:)
    • [3.2 实现代码如下:](#3.2 实现代码如下:)
    • [3.3 application.yml配置](#3.3 application.yml配置)
    • [3.4 测试](#3.4 测试)

1. Predicate Factories介绍

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

启动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值用逗号分隔
YAML 复制代码
spring:
  cloud:
    gateway:
      routes:
        - id: payRoute                  
          uri: lb://payment              
          predicates:
            - Path=/pay/**              
            - Cookie=cookieKey,cookieValue  # 需同时匹配Path和Cookie,HTTP请求的Cookie的key需要为cookieKey,value需要为cookieValue
  • 全部展开语法
YAML 复制代码
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 实现代码如下:

Java 复制代码
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配置

全部展开语法配置如下:

YAML 复制代码
            - 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请求成功

相关推荐
蓝眸少年CY3 小时前
(第十二篇)spring cloud之Stream消息驱动
后端·spring·spring cloud
南朝雨9 小时前
Spring Boot Admin日志监控坑点:远程配置的logging.file.name为何生效又失效?
java·spring boot·spring cloud·微服务·logback
深入技术了解原理11 小时前
eureka-client依赖爆红无法下载
spring cloud·云原生·eureka
ZePingPingZe11 小时前
深入理解网络模型之Spring Cloud微服务通信、Socket、HTTP与RPC
网络协议·spring cloud·rpc·dubbo
叫码农就行11 小时前
spring cloud 笔记
java·笔记·spring cloud
七夜zippoe12 小时前
微服务架构演进实战 从单体到微服务的拆分原则与DDD入门
java·spring cloud·微服务·架构·ddd·绞杀者策略
Leo July1 天前
【Java】Spring Cloud 微服务生态全解析与企业级架构实战
java·spring cloud
一条咸鱼_SaltyFish1 天前
WebFlux vs MVC:Gateway集成若依框架的技术选型之争
java·开发语言·微服务·gateway·mvc·开源软件·webflux
李慕婉学姐1 天前
【开题答辩过程】以《基于springcloud的空气质量监控管理系统》为例,不知道这个选题怎么做的,不知道这个选题怎么开题答辩的可以进来看看
后端·spring·spring cloud