当前位置: 首页 > news >正文

分布式微服务--GateWay的断言以及如何自定义一个断言

📌 一、什么是 Gateway 的断言(Predicates)?

Predicates(断言) 是 Spring Cloud Gateway 中用于匹配请求的条件。只有请求满足断言条件,路由才会生效,转发到下游服务。


🎯 二、常见内置断言类型

断言类型示例配置对应断言工厂类说明
PathPath=/api/**PathRoutePredicateFactory匹配请求路径(支持通配符)
MethodMethod=GETMethodRoutePredicateFactory匹配请求方法(GET、POST等)
HeaderHeader=Auth, \w+HeaderRoutePredicateFactory匹配请求头,支持正则
QueryQuery=tokenQueryRoutePredicateFactory匹配 URL 查询参数(?key=value)
HostHost=**.example.comHostRoutePredicateFactory匹配请求 Host(域名)
CookieCookie=sessionId, \w+CookieRoutePredicateFactory匹配请求中的 Cookie
RemoteAddrRemoteAddr=192.168.0.1/24RemoteAddrRoutePredicateFactory匹配客户端 IP(支持 CIDR)
AfterAfter=2025-08-01T00:00:00+08:00AfterRoutePredicateFactory匹配某个时间之后的请求
BeforeBefore=2025-09-01T00:00:00+08:00BeforeRoutePredicateFactory匹配某个时间之前的请求
BetweenBetween=2025-08-01T00:00:00+08:00, 2025-08-31T23:59:59+08:00BetweenRoutePredicateFactory匹配时间范围内的请求
WeightWeight=group1, 80WeightRoutePredicateFactory灰度发布、流量权重控制

📦 三、断言使用方式(YAML 示例)

spring:cloud:gateway:routes:- id: user_routeuri: http://localhost:8081predicates:- Path=/user/**- Method=GET

🧱 四、自定义断言的必要性

当内置断言不能满足个性化业务需求时,例如:

  • 用户权限判断

  • 参数动态校验

  • 黑白名单过滤

  • 特定设备访问限制

就需要创建自定义断言。


🔧 五、自定义断言步骤(按请求参数控制)

✅ 目标:

只有当请求参数中 allow=true 时才允许路由。


📄 第一步:创建断言类

注意对于

//是1  return new Predicate<ServerWebExchange>() {
//还是2 return new GatewayPredicate() {return new GatewayPredicate() {@Overridepublic 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 接口,用于扩展断言工厂。

package 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 AllowParamRoutePredicateFactoryextends AbstractRoutePredicateFactory<AllowParamRoutePredicateFactory.Config> {public AllowParamRoutePredicateFactory() {super(Config.class);}//方式一 Lambda 表达式形式@Overridepublic Predicate<ServerWebExchange> apply(Config config) {return exchange -> {String value = exchange.getRequest().getQueryParams().getFirst(config.getParam());return config.getExpectedValue() != null && config.getExpectedValue().equals(value);};}//方式二 匿名内部类形式@Overridepublic Predicate<ServerWebExchange> apply(Config config) {return new Predicate<ServerWebExchange>() {@Overridepublic boolean test(ServerWebExchange exchange) {String value = exchange.getRequest().getQueryParams().getFirst(config.getParam());return config.getExpectedValue() != null && config.getExpectedValue().equals(value);}};
}@Overridepublic List<String> shortcutFieldOrder() {return Arrays.asList("param", "expectedValue");}@Data@NoArgsConstructorpublic static class Config {private String param;private String expectedValue;}
}

🧾 第二步:配置文件中使用

spring:cloud:gateway:routes:- id: allow_param_routeuri: http://localhost:8081predicates:#这个名称必须与AllowParamRoutePredicateFactory所匹配否则匹配不上#也就是说自定义拦截器叫HhRoutePredicateFactory#下面也要写成Hh=name,value - AllowParam=allow, true

🧪 第三步:访问测试

  • http://localhost:9000/test?allow=true → 匹配成功,转发到下游服务

  • http://localhost:9000/test?allow=false → 匹配失败,不转发


🧠 六、重点解释:值是怎么传入 config 的?

配置值注入原理:

  1. Spring Boot 自动读取 AllowParamRoutePredicateFactory

  2. 发现其内部的 Config 类中包含字段:paramexpectedValue

  3. 调用方法:

    @Override
    public List<String> shortcutFieldOrder() {return Arrays.asList("param", "expectedValue");
    }
    
  4. YAML 配置:

AllowParam=allow, true

➡️ 会自动赋值为:

config.param = "allow";
config.expectedValue = "true";

🧠 七、两行核心逻辑详解

String 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 判断是否来自移动端
限制访问时间判断当前时间是否处于营业时间
http://www.lryc.cn/news/614268.html

相关文章:

  • MySQL 配置性能优化赛:核心策略与实战技巧
  • 分布式系统性能优化实战:从瓶颈定位到架构升级
  • 前端后端之争?JavaScript和Java的特性与应用场景解析
  • Microsoft Dynamics AX 性能优化解决方案
  • 用JOIN替代子查询的查询性能优化
  • 深入解析基于Zookeeper分布式锁在高并发场景下的性能优化实践指南
  • DataFun联合开源AllData社区和开源Gravitino社区将在8月9日相聚数据治理峰会论坛
  • AI漫画翻译器-上传图片自动翻译,支持多语言
  • 分享超图提供的、很不错的WebGIS学习资源
  • 从安卓兼容性困境到腾讯Bugly的救赎:全链路崩溃监控解决方案-卓伊凡|bigniu
  • 什么是局放?局放在线智能传感器,敏锐洞察电气设备中的隐形故障!
  • bytearray和bytes
  • 进程管理、系统高负载、cpu超过800%等实战问题处理
  • 【Mybatis入门】配置Mybatis(IDEA)
  • scratch笔记和练习-第11课:穿越峡谷
  • [Linux]学习笔记系列 -- [arm[kernel]
  • Godot ------ 中级人物血条制作02
  • ABP VNext + Fody AOP:编译期织入与性能监控
  • 当服务器多了时,如何管理?
  • 服务器快照与备份的本质区别及正确使用指南 (2025)
  • Linux 内核发包流程与路由控制实战
  • VMwareWorkstation17Pro安装CentOS8无法连接外网问题
  • python使用python-docx自动化操作word
  • Ideogram:优秀的在线AI绘画平台
  • 自由学习记录(79)
  • 3D TOF 视觉相机:工业视觉的破局者,重塑视觉感知的未来
  • 动态规划进阶:转移方程优化技巧全解
  • 二、RuoYi-Cloud-Plus 拉取到本地的准备和注意事项
  • AcWing 6478. 谁进线下了?III
  • C++使用FFmpeg进行视频推流