📌 一、什么是 Gateway 的断言(Predicates)?
Predicates(断言) 是 Spring Cloud Gateway 中用于匹配请求的条件。只有请求满足断言条件,路由才会生效,转发到下游服务。
🎯 二、常见内置断言类型
| | 断言类型 | 示例配置 | 对应断言工厂类 | 说明 | |--------------|----------------------------------------------------------------|-----------------------------------|-------------------------| |
Path
|Path=/api/**
|PathRoutePredicateFactory
| 匹配请求路径(支持通配符) | |Method
|Method=GET
|MethodRoutePredicateFactory
| 匹配请求方法(GET、POST等) | |Header
|Header=Auth, \w+
|HeaderRoutePredicateFactory
| 匹配请求头,支持正则 | |Query
|Query=token
|QueryRoutePredicateFactory
| 匹配 URL 查询参数(?key=value) | |Host
|Host=**.example.com
|HostRoutePredicateFactory
| 匹配请求 Host(域名) | |Cookie
|Cookie=sessionId, \w+
|CookieRoutePredicateFactory
| 匹配请求中的 Cookie | |RemoteAddr
|RemoteAddr=192.168.0.1/24
|RemoteAddrRoutePredicateFactory
| 匹配客户端 IP(支持 CIDR) | |After
|After=2025-08-01T00:00:00+08:00
|AfterRoutePredicateFactory
| 匹配某个时间之后的请求 | |Before
|Before=2025-09-01T00:00:00+08:00
|BeforeRoutePredicateFactory
| 匹配某个时间之前的请求 | |Between
|Between=2025-08-01T00:00:00+08:00, 2025-08-31T23:59:59+08:00
|BetweenRoutePredicateFactory
| 匹配时间范围内的请求 | |Weight
|Weight=group1, 80
|WeightRoutePredicateFactory
| 灰度发布、流量权重控制 | |
|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
📦 三、断言使用方式(YAML 示例)
javaspring: cloud: gateway: routes: - id: user_route uri: http://localhost:8081 predicates: - Path=/user/** - Method=GET
🧱 四、自定义断言的必要性
当内置断言不能满足个性化业务需求时,例如:
用户权限判断
参数动态校验
黑白名单过滤
特定设备访问限制
就需要创建自定义断言。
🔧 五、自定义断言步骤(按请求参数控制)
✅ 目标:
只有当请求参数中
allow=true
时才允许路由。
📄 第一步:创建断言类
注意对于:
java//是1 return new Predicate<ServerWebExchange>() { //还是2 return new GatewayPredicate() { return new GatewayPredicate() { @Override public boolean test(ServerWebExchange exchange) { String value = exchange.getRequest().getQueryParams().getFirst(config.getParam()); return config.getExpectedValue() != null && config.getExpectedValue().equals(value); }
2.0.x.RELEASE
:✅ 有Predicate<ServerWebExchange>
,但没有GatewayPredicate
。
2.1.0.RELEASE
及以后:✅ 增加了GatewayPredicate
接口,用于扩展断言工厂。
javapackage com.example.gateway.predicates; import lombok.Data; import lombok.NoArgsConstructor; import org.springframework.cloud.gateway.handler.predicate.AbstractRoutePredicateFactory; import org.springframework.stereotype.Component; import org.springframework.web.server.ServerWebExchange; import java.util.function.Predicate; @Component public class AllowParamRoutePredicateFactory extends AbstractRoutePredicateFactory<AllowParamRoutePredicateFactory.Config> { public AllowParamRoutePredicateFactory() { super(Config.class); } //方式一 Lambda 表达式形式 @Override public Predicate<ServerWebExchange> apply(Config config) { return exchange -> { String value = exchange.getRequest().getQueryParams().getFirst(config.getParam()); return config.getExpectedValue() != null && config.getExpectedValue().equals(value); }; } //方式二 匿名内部类形式 @Override public Predicate<ServerWebExchange> apply(Config config) { return new Predicate<ServerWebExchange>() { @Override public boolean test(ServerWebExchange exchange) { String value = exchange.getRequest().getQueryParams().getFirst(config.getParam()); return config.getExpectedValue() != null && config.getExpectedValue().equals(value); } }; } @Override public List<String> shortcutFieldOrder() { return Arrays.asList("param", "expectedValue"); } @Data @NoArgsConstructor public static class Config { private String param; private String expectedValue; } }
🧾 第二步:配置文件中使用
javaspring: cloud: gateway: routes: - id: allow_param_route uri: http://localhost:8081 predicates: #这个名称必须与AllowParamRoutePredicateFactory所匹配否则匹配不上 #也就是说自定义拦截器叫HhRoutePredicateFactory #下面也要写成Hh=name,value - AllowParam=allow, true
🧪 第三步:访问测试
✅
http://localhost:9000/test?allow=true
→ 匹配成功,转发到下游服务❌
http://localhost:9000/test?allow=false
→ 匹配失败,不转发
🧠 六、重点解释:值是怎么传入 config 的?
配置值注入原理:
Spring Boot 自动读取
AllowParamRoutePredicateFactory
类发现其内部的
Config
类中包含字段:param
和expectedValue
调用方法:
java@Override public List<String> shortcutFieldOrder() { return Arrays.asList("param", "expectedValue"); }
YAML 配置:
javaAllowParam=allow, true
➡️ 会自动赋值为:
javaconfig.param = "allow"; config.expectedValue = "true";
🧠 七、两行核心逻辑详解
javaString value = exchange.getRequest().getQueryParams().getFirst(config.getParam()); return config.getExpectedValue().equals(value);
第一句:从请求参数中取出
config.param
指定的参数名的值第二句:判断这个值是否等于配置中
expectedValue
🔒 八、为什么写成断言而不是过滤器?
对比项 断言(Predicate) 过滤器(Filter) 作用时机 匹配路由前 路由匹配之后 是否转发 决定是否进入路由 已经进入路由,处理请求/响应 使用目的 控制路由是否生效(入门条件) 日志、限流、鉴权、响应处理等增强功能 推荐用途 参数控制、角色控制、AB测试等 认证授权、限流、Header 修改、响应包装等
✅ 九、总结
项目 内容 自定义断言基类 AbstractRoutePredicateFactory
配置值映射方式 shortcutFieldOrder()
定义参数顺序触发时机 请求进入网关、匹配路由之前 使用场景 请求参数判断、设备识别、用户等级判断等 与 Filter 区别 Predicate 决定"要不要路由",Filter 是增强 核心逻辑建议 加入 null 判断,防止 NPE
🧰 十、可扩展场景建议
业务场景 自定义断言建议逻辑 按用户权限分流 从 JWT 中解析权限字段,判断是否匹配 灰度发布 用户 ID 做 hash 取模,实现 10% 的灰度流量 手机访问拦截 通过 User-Agent 判断是否来自移动端 限制访问时间 判断当前时间是否处于营业时间
分布式微服务--GateWay的断言以及如何自定义一个断言
你我约定有三2025-08-09 12:58