目录
- [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.0
到72.108.25.255
;72.109.25.2/30
无类域间路由表示前30位是网络地址,则只有2位是主机地址,所以主机范围为72.109.25.0
到72.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
请求成功
- CIDR(无类域间路由):支持IPV4和IPV6, 一个形如
- 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 实现步骤:
- 在gatewayServer项目中新建自定义Predicate Factory类
MyRoutePredicateFactory
。类名的后缀必须是RoutePredicateFactory。所以这里创建的是一个My Route Predicate - 类继承
AbstractRoutePredicateFactory
。也可以继承RoutePredicateFactory
接口 - 实现无参构造器,调用父类的构造器
- 实现一个配置类
MyRoutePredicateFactory.Config
,定义需要验证的值userType
- 重写父类的
apply
方法,实现匹配userType成功和失败的逻辑 - 重写父类的
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
请求成功