0%

GateWay断言

Spring Cloud Gateway 断言(Predicate)详解:精准匹配请求的核心机制

Spring Cloud Gateway 的断言(Predicate)是路由匹配的核心,它通过匹配 HTTP 请求的各种属性(如路径、方法、头信息、时间等),决定是否将请求转发到目标服务。Gateway 内置了多种断言工厂,满足不同场景的路由匹配需求。

断言的本质

断言(Predicate)本质是请求匹配规则,基于 Java 8 的Predicate函数式接口实现。当请求到达网关时,Gateway 会依次执行路由中定义的断言:

  • 若所有断言均返回true,则请求匹配该路由,执行转发;
  • 若任一断言返回false,则跳过该路由,继续匹配其他路由。

断言的配置方式有两种:

  1. 简短配置- 断言名=参数1,参数2(适合简单场景);
  2. 全面配置:通过nameargs显式指定参数(适合复杂场景)。

示例(Cookie 断言的两种配置):

1
2
3
4
5
6
7
8
9
10
# 简短配置
predicates:
- Cookie=userName, zhangsan

# 全面配置
predicates:
- name: Cookie
args:
name: userName
regexp: zhangsan

常用断言详解

Gateway 内置了 10 余种断言工厂,以下是最常用的几种:

1. 时间类断言:基于请求时间匹配

(1)After 断言

匹配在指定时间之后的请求。

1
2
3
predicates:
# 匹配2024-01-01 00:00:00之后的请求(时区Asia/Shanghai)
- After=2024-01-01T00:00:00+08:00[Asia/Shanghai]
  • 格式:After=时间字符串(时间格式为yyyy-MM-ddTHH:mm:ss±HH:MM[时区])。
(2)Before 断言

匹配在指定时间之前的请求。

1
2
3
predicates:
# 匹配2024-12-31 23:59:59之前的请求
- Before=2024-12-31T23:59:59+08:00[Asia/Shanghai]
(3)Between 断言

匹配在两个时间之间的请求。

1
2
3
predicates:
# 匹配2024-01-01到2024-12-31之间的请求
- Between=2024-01-01T00:00:00+08:00[Asia/Shanghai], 2024-12-31T23:59:59+08:00[Asia/Shanghai]

2. 请求属性类断言:基于 HTTP 请求信息匹配

(1)Path 断言(最常用)

匹配请求路径(支持通配符)。

1
2
3
4
5
predicates:
# 匹配/dept/开头的路径(如/dept/get/1、/dept/list)
- Path=/dept/**
# 多路径匹配(/user/或/order/开头)
- Path=/user/**,/order/**
  • 通配符规则:*匹配单层路径,**匹配多层路径(如/dept/*匹配/dept/1,但不匹配/dept/1/info)。
(2)Method 断言

匹配指定的 HTTP 方法(如 GET、POST)。

1
2
3
predicates:
# 仅允许GET和POST请求
- Method=GET,POST
(3)Query 断言

匹配请求参数(支持正则表达式)。

1
2
3
4
5
predicates:
# 匹配包含参数id,且值为数字的请求(如?id=123)
- Query=id, \d+
# 仅匹配包含参数name的请求(不限制值)
- Query=name
(4)Header 断言

匹配请求头(支持正则表达式)。

1
2
3
predicates:
# 匹配包含X-Request-Id头,且值为数字的请求
- Header=X-Request-Id, \d+
(5)Cookie 断言

匹配 Cookie(支持正则表达式)。

1
2
3
predicates:
# 匹配包含userName=zhangsan的Cookie
- Cookie=userName, zhangsan

3. 网络类断言:基于请求来源匹配

(1)RemoteAddr 断言

匹配请求的客户端 IP 地址。

1
2
3
predicates:
# 匹配IP在192.168.1.0/24网段的请求(如192.168.1.100)
- RemoteAddr=192.168.1.1/24
  • 格式:支持 IP 地址或 CIDR 网段(如10.0.0.0/8)。
(2)Host 断言

匹配请求的 Host 域名(支持 Ant 风格通配符)。

1
2
3
predicates:
# 匹配*.example.com或*.demo.org的域名(如api.example.com、www.demo.org)
- Host=**.example.com,**.demo.org

4. 路由权重类断言:Weight 断言

用于实现权重路由,按比例将请求分发到不同目标服务(灰度发布常用)。

1
2
3
4
5
6
7
8
9
10
11
routes:
# 80%的请求路由到weighthigh.org
- id: weight_high
uri: https://weighthigh.org
predicates:
- Weight=group1, 8 # group1为分组名,8为权重
# 20%的请求路由到weightlow.org
- id: weight_low
uri: https://weightlow.org
predicates:
- Weight=group1, 2 # 同一分组内权重总和为10(8+2)
  • 同一分组(如group1)的权重总和为比例分母,单个路由的权重为分子。

断言的组合使用

多个断言可以组合使用,所有断言必须同时满足才会匹配路由。

示例:仅允许工作时间(9:00-18:00)的 GET 请求访问/api/**路径:

1
2
3
4
5
6
7
routes:
- id: combined_route
uri: lb://api-service
predicates:
- Path=/api/** # 路径匹配
- Method=GET # 方法匹配
- Between=2024-01-01T09:00:00+08:00[Asia/Shanghai], 2024-12-31T18:00:00+08:00[Asia/Shanghai] # 时间匹配

自定义断言(扩展)

若内置断言无法满足需求,可自定义断言工厂,步骤如下:

  1. 创建配置类:定义断言所需参数;
  2. 实现RoutePredicateFactory:重写apply方法,编写匹配逻辑;
  3. 注册为 Spring Bean:通过@Component注解生效。

示例:自定义 “请求头包含版本号” 的断言:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
// 1. 配置类(存储参数)
public static class Config {
private String version;

// getter和setter
}

// 2. 自定义断言工厂
@Component
public class VersionRoutePredicateFactory extends AbstractRoutePredicateFactory<VersionRoutePredicateFactory.Config> {

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

@Override
public Predicate<ServerWebExchange> apply(Config config) {
// 匹配逻辑:请求头包含X-Version且值等于配置的version
return exchange -> {
String version = exchange.getRequest().getHeaders().getFirst("X-Version");
return version != null && version.equals(config.getVersion());
};
}

// 配置参数解析(指定参数名和顺序)
@Override
public List<String> shortcutFieldOrder() {
return Collections.singletonList("version");
}
}

使用自定义断言:

1
2
predicates:
- Version=v1 # 匹配X-Version=v1的请求

总结

Gateway 的断言是实现精准路由的核心,通过内置的时间、路径、方法、权重等断言,可满足大多数场景的路由匹配需求

欢迎关注我的其它发布渠道