GateWay断言

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

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

断言的本质

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

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

断言的配置方式有两种:

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

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

# 简短配置
predicates:
  - Cookie=userName, zhangsan

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

常用断言详解

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

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

(1)After 断言

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

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 断言

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

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

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

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 断言(最常用)

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

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

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

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

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

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

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

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

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

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

(1)RemoteAddr 断言

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

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 风格通配符)。

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

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

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

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/**路径:

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. 配置类(存储参数)
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");
    }
}

使用自定义断言:

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

总结

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