当前位置: 首页 > 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.dtcms.com/a/320780.html

相关文章:

  • 【昇腾】基于RK3588 arm架构Ubuntu22.04系统上适配Atlas 200I A2加速模块安装EP模式下的驱动固件包_20250808
  • simulink tlc如何通过tlc写数据入文件
  • 三种 SSE 对比
  • 秋招笔记-8.8
  • Django模型开发全解析:字段、元数据与继承的实战指南
  • C++简单项目跟练【通讯录管理系统000】
  • 持中文的 TXT 合并 PDF 工具 —— GUI + ReportLab 实战
  • 基于定制开发开源AI智能名片S2B2C商城小程序的定价策略与市场定位研究
  • UniApp Vue3 TypeScript项目中使用xgplayer播放m3u8视频的显示问题
  • AI学习笔记三十五:实时传输视频
  • webrtc弱网-EncodeUsageResource类源码分析及算法原理
  • Baumer相机如何通过YoloV8深度学习模型实现高速公路车辆的实时检测计数(C#代码UI界面版)
  • 云原生时代的 Linux:容器、虚拟化与分布式的基石
  • 深入理解VideoToolbox:iOS/macOS视频硬编解码实战指南
  • 微软公布Windows 2030,要彻底淘汰鼠标、键盘
  • token过期为了保证安全,refresh token不过期,那么拿到refresh token就可以获取token,不还是不安全吗
  • 今日行情明日机会——20250808
  • 座舱HMI软件开发架构:核心功能与案例解析
  • 【重学MySQL】事务隔离
  • OLE延时剪切板技术深度解析:从资源管理器支持到远程桌面文件同步 含c++ demo代码 亲测可用
  • R语言代码加密(1)
  • 贪心(set维护)
  • React函数组件灵魂搭档:useEffect深度通关指南!
  • Docker容器部署discuz论坛与线上商城
  • 项目一系列-第2章 Git版本控制
  • 05--STL认识(了解)
  • 静态与动态住宅代理IP的技术差异和技术详解
  • Pytest项目_day09(skip、skipif跳过)
  • oracle-plsql理解和操作
  • 有鹿机器人:如何用±2cm精度重塑行业标准?