文章目录
-
- 一、开篇:路由是网关的"灵魂"
- 二、路由配置的两种方式
-
- [2.1 2025版配置前缀变更(必读)](#2.1 2025版配置前缀变更(必读))
- [2.2 快捷配置 vs 完全展开](#2.2 快捷配置 vs 完全展开)
- 三、内置谓词工厂详解
-
- [3.1 Path谓词(最常用)](#3.1 Path谓词(最常用))
- [3.2 Method谓词](#3.2 Method谓词)
- [3.3 Header谓词](#3.3 Header谓词)
- [3.4 Query谓词](#3.4 Query谓词)
- [3.5 Cookie谓词](#3.5 Cookie谓词)
- [3.6 Host谓词](#3.6 Host谓词)
- [3.7 时间类谓词:After / Before / Between](#3.7 时间类谓词:After / Before / Between)
- [3.8 RemoteAddr谓词](#3.8 RemoteAddr谓词)
- [3.9 Weight谓词(权重路由)](#3.9 Weight谓词(权重路由))
- 四、路径重写与灰度路由实战
-
- [4.1 RewritePath路径重写](#4.1 RewritePath路径重写)
- [4.2 灰度路由完整实战](#4.2 灰度路由完整实战)
- 五、自定义谓词工厂实战
-
- [5.1 核心实现步骤](#5.1 核心实现步骤)
- [5.2 实战:VIP用户灰度谓词工厂](#5.2 实战:VIP用户灰度谓词工厂)
- [5.3 配置使用](#5.3 配置使用)
- [5.4 自定义谓词不生效的常见原因](#5.4 自定义谓词不生效的常见原因)
- 六、踩坑指南
- 七、课后作业
- 八、下节预告
- [🔗《最新版 SpringCloud 2025 从入门到实战》系列课程导航](#🔗《最新版 SpringCloud 2025 从入门到实战》系列课程导航)

适配版本 :Spring Cloud Gateway 5.0.0、Spring Cloud 2025.1.3(Oakwood)、Spring Boot 4.0.8、Spring Cloud Alibaba 2025.1.0.0、JDK 21
课程定位:网关核心能力实战,从路由配置到内置谓词,从路径重写到自定义谓词工厂,掌握路由规则的全部关键点
一、开篇:路由是网关的"灵魂"
第17课我们完成了Gateway的架构认知:理解了Reactor-Netty异步原理,梳理了请求五阶段流转链路,掌握了2025版双栈架构和配置前缀变更。现在进入Gateway最核心的能力------路由。
路由解决的是一个基本问题:什么样的请求,转发到哪个服务。看起来简单,实则不然。真实的业务场景中,路由规则往往非常复杂:只有携带特定Header的灰度用户才路由到新版本;只有来自内网IP的请求才允许访问管理接口;只在秒杀时间段内才路由到秒杀服务;不同App版本的用户路由到不同后端。
这些问题,都需要通过谓词(Predicate) 来精细控制。Gateway内置了十余种谓词工厂,覆盖路径、方法、Header、Cookie、时间、权重、远程地址等几乎所有HTTP请求属性。当内置谓词无法满足需求时,还可以自定义谓词工厂。
本课将从路由配置的基础讲起,逐一剖析内置谓词的用法,实战路径重写、权重路由和灰度路由,最后手把手教你实现自定义谓词工厂。需要特别注意的是:Gateway 5.0的配置前缀发生了根本性变更,沿用旧前缀会导致路由完全不生效------这是本课第一个必须掌握的知识点。
二、路由配置的两种方式
2.1 2025版配置前缀变更(必读)
在动手配置路由之前,必须确认一件事:配置前缀已经变了。
| 版本 | 配置前缀 |
|---|---|
| Gateway 4.x(旧) | spring.cloud.gateway.* |
| Gateway 5.x(新) | spring.cloud.gateway.server.webflux.* |
源码中GatewayProperties.PREFIX的值已变更为spring.cloud.gateway.server.webflux。如果不迁移前缀,路由配置静默不生效 ------启动不会报错,但访问时返回404,日志中只有No RouteDefinition found。
旧写法(Gateway 5.x不认) :
yaml
# ❌ 无效配置
spring:
cloud:
gateway:
routes:
- id: user_route
uri: lb://service-user
新写法(Gateway 5.x正确) :
yaml
# ✅ 正确配置
spring:
cloud:
gateway:
server:
webflux:
routes:
- id: user_route
uri: lb://service-user
predicates:
- Path=/api/user/**
踩坑提示 :可以临时引入
spring-boot-properties-migrator来兼容旧前缀,但建议立即迁移到新前缀。旧前缀将在未来版本中彻底移除。
2.2 快捷配置 vs 完全展开
Gateway提供了两种谓词配置方式:快捷方式 和完全展开方式。
快捷配置通过谓词名称识别,后跟等号,再跟逗号分隔的参数值:
yaml
spring:
cloud:
gateway:
server:
webflux:
routes:
- id: user_route
uri: lb://service-user
predicates:
- Path=/api/user/**
- Method=GET
完全展开的参数 更接近标准YAML,使用name和args键值对:
yaml
spring:
cloud:
gateway:
server:
webflux:
routes:
- id: user_route
uri: lb://service-user
predicates:
- name: Path
args:
patterns: /api/user/**
- name: Method
args:
methods: GET
两种方式的选型建议:简单谓词用快捷方式,配置简洁;复杂谓词(如多个Path模式、带正则的参数)用完全展开方式,避免逗号分隔导致的歧义。
三、内置谓词工厂详解
Spring Cloud Gateway内置了十余种路由谓词工厂,所有谓词都与HTTP请求的不同属性匹配,多个谓词之间通过AND逻辑组合------请求必须同时满足所有谓词条件才会被路由。
3.1 Path谓词(最常用)
匹配请求路径模式,是日常开发中使用频率最高的谓词。
yaml
predicates:
- Path=/api/user/**
- Path=/api/order/**,/api/payment/**
Path谓词支持/**通配符和{segment}路径变量。如果需要更灵活的正则匹配(如匹配任意层级路径),可以自定义AntPathRoutePredicateFactory,使用AntPathMatcher替代默认的PathPatternParser。
3.2 Method谓词
匹配HTTP请求方法:
yaml
predicates:
- Method=GET,POST
3.3 Header谓词
匹配请求头中的参数名和值(支持正则表达式):
yaml
predicates:
- Header=X-Request-Id, \d+
- Header=Authorization, Bearer.*
典型应用场景 :灰度路由------只有携带X-Gray-Version: v2的请求才路由到新版本服务。
3.4 Query谓词
匹配URL查询参数:
yaml
predicates:
- Query=name, Jack
- Query=debug
第二个参数为正则表达式,不填写时表示只要存在该参数即匹配。
3.5 Cookie谓词
匹配请求Cookie:
yaml
predicates:
- Cookie=JSESSIONID, [a-z0-9]+
3.6 Host谓词
匹配请求Host头:
yaml
predicates:
- Host=**.example.com
3.7 时间类谓词:After / Before / Between
基于请求时间进行匹配,常用于限时活动场景:
yaml
predicates:
# 2030年1月20日之后才路由
- After=2030-01-20T17:42:47.789-07:00[America/Denver]
# 秒杀时间段内才路由
- Between=2026-11-11T00:00:00+08:00[Asia/Shanghai], 2026-11-11T23:59:59+08:00[Asia/Shanghai]
时间格式为ZonedDateTime,可用System.out.println(ZonedDateTime.now())打印当前时区格式。
3.8 RemoteAddr谓词
匹配客户端IP地址(支持CIDR格式):
yaml
predicates:
- RemoteAddr=192.168.1.1/24
典型应用场景:只有内网IP才能访问管理接口。
3.9 Weight谓词(权重路由)
Weight谓词用于灰度发布,根据权重将流量分配到不同版本的服务实例。同一分组内的所有路由权重之和应为100:
yaml
spring:
cloud:
gateway:
server:
webflux:
routes:
- id: user_v1
uri: lb://service-user-v1
predicates:
- Path=/api/user/**
- Weight=user-group, 95
- id: user_v2
uri: lb://service-user-v2
predicates:
- Path=/api/user/**
- Weight=user-group, 5
上述配置将95%的流量路由到v1版本,5%路由到v2版本。灰度验证通过后,逐步调整权重直至v2全量。
四、路径重写与灰度路由实战
4.1 RewritePath路径重写
路径重写用于将外部暴露的URL路径转换为后端服务实际接收的路径。例如前端调用/api/user/1,后端服务实际接收/user/1(去掉/api前缀):
yaml
spring:
cloud:
gateway:
server:
webflux:
routes:
- id: user_route
uri: lb://service-user
predicates:
- Path=/api/user/**
filters:
- RewritePath=/api/user/(?<segment>.*), /user/${segment}
正则命名捕获组 :(?<segment>.*)捕获/api/user/之后的所有内容,${segment}在替换表达式中引用该值。
4.2 灰度路由完整实战
灰度路由的核心思想是:通过请求特征识别灰度用户,将灰度用户路由到新版本。
方案一:基于Header的灰度路由
yaml
spring:
cloud:
gateway:
server:
webflux:
routes:
- id: user_gray
uri: lb://service-user-v2
predicates:
- Path=/api/user/**
- Header=X-Gray-Version, v2
- id: user_normal
uri: lb://service-user-v1
predicates:
- Path=/api/user/**
order: 10 # order越小优先级越高,正常路由作为兜底
关键规则 :灰度路由的order值应小于 正常路由的order值,确保灰度请求优先匹配。未携带灰度Header的请求自动落入正常路由。
方案二:基于权重的灰度路由
如前文3.9节所示,通过Weight谓词按比例分配流量,适合"不区分用户,只按比例灰度"的场景。
方案三:基于Cookie的灰度路由
yaml
predicates:
- Path=/api/user/**
- Cookie=gray, true
方案四:组合条件灰度路由
实际生产中,灰度规则往往是组合的。例如:内网用户 + 特定App版本才路由到新版本:
yaml
predicates:
- Path=/api/user/**
- RemoteAddr=192.168.1.0/24
- Header=X-App-Version, 2\.0\..*
五、自定义谓词工厂实战
当内置谓词无法满足复杂业务需求时(如需要查询数据库、解析JWT、判断用户VIP等级),需要实现自定义谓词工厂。
5.1 核心实现步骤
实现自定义谓词工厂需要四步:
步骤一:继承AbstractRoutePredicateFactory<Config>。
步骤二:定义静态内部类Config ,用于接收YAML中的配置参数。
步骤三:实现apply(Config)方法 ,返回一个Predicate<ServerWebExchange>。
步骤四:覆盖shortcutFieldOrder()方法(可选但推荐),定义快捷配置的字段顺序。
5.2 实战:VIP用户灰度谓词工厂
需求:根据请求头中的用户等级,只有VIP用户才路由到新版本服务。
java
package com.example.microservice.gateway.predicate;
import org.springframework.cloud.gateway.handler.predicate.AbstractRoutePredicateFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import java.util.List;
import java.util.function.Predicate;
@Component
public class VipRoutePredicateFactory
extends AbstractRoutePredicateFactory<VipRoutePredicateFactory.Config> {
public VipRoutePredicateFactory() {
super(Config.class);
}
@Override
public List<String> shortcutFieldOrder() {
return List.of("level");
}
@Override
public Predicate<ServerWebExchange> apply(Config config) {
return exchange -> {
String userLevel = exchange.getRequest()
.getHeaders().getFirst("X-User-Level");
if (userLevel == null) {
return false;
}
// 比较用户等级是否达到要求(如 GOLD 匹配 GOLD 和 DIAMOND)
return compareLevel(userLevel, config.getLevel());
};
}
private boolean compareLevel(String actual, String required) {
List<String> levels = List.of("NORMAL", "SILVER", "GOLD", "DIAMOND");
int actualIdx = levels.indexOf(actual.toUpperCase());
int requiredIdx = levels.indexOf(required.toUpperCase());
return actualIdx >= requiredIdx && requiredIdx >= 0;
}
@Validated
public static class Config {
private String level;
public String getLevel() { return level; }
public void setLevel(String level) { this.level = level; }
}
}
关键规范:
- 类名必须以
RoutePredicateFactory结尾,如VipRoutePredicateFactory - 谓词名称对应类名前缀:
VipRoutePredicateFactory→ 配置中使用Vip= shortcutFieldOrder()返回的字段顺序决定了快捷配置中参数的顺序
5.3 配置使用
yaml
spring:
cloud:
gateway:
server:
webflux:
routes:
- id: user_vip_gray
uri: lb://service-user-v2
predicates:
- Path=/api/user/**
- Vip=GOLD
快捷配置 :Vip=GOLD会将GOLD自动映射到Config.level字段。
完全展开配置:
yaml
predicates:
- name: Vip
args:
level: GOLD
5.4 自定义谓词不生效的常见原因
| 问题 | 原因 | 解决 |
|---|---|---|
| 谓词完全未匹配 | 未注册为Spring Bean | 添加@Component注解 |
| 配置解析失败 | 类名未以RoutePredicateFactory结尾 |
遵循命名规范 |
| 参数值未注入 | 未覆盖shortcutFieldOrder() |
实现该方法并返回字段列表 |
| 匹配逻辑异常 | apply()中抛出异常 |
添加空值检查和异常捕获 |
六、踩坑指南
坑一:配置前缀未迁移导致路由静默失效
现象 :启动无报错,但所有路由返回404,日志中只有No RouteDefinition found。
原因 :使用了旧的spring.cloud.gateway.routes前缀,而Gateway 5.x要求spring.cloud.gateway.server.webflux.routes。
解决 :迁移到新前缀,或临时引入spring-boot-properties-migrator兼容。这个问题没有任何报错提示,是最隐蔽的坑,必须第一优先级排查。
坑二:Path谓词正则表达式不匹配多级路径
现象 :Path=/(.*)/test-file.js无法匹配/segment1/segment2/test-file.js。
原因 :Gateway 5.x默认使用PathPatternParser,不支持任意层级正则匹配。
解决 :自定义AntPathRoutePredicateFactory,使用AntPathMatcher替代,配置AntPath=/**/test-file.js。
坑三:Weight权重路由不生效
现象:配置了Weight谓词,但流量仍然全部路由到一个版本。
原因 :同一分组内的路由必须同时配置Weight谓词,且权重之和为100。如果只有一个路由配置了Weight,流量会全部走该路由。
解决 :确保同一Weight=groupName, weight分组下所有路由都配置了Weight谓词。
坑四:自定义谓词类名不规范导致配置解析失败
现象 :自定义谓词在YAML中配置后启动报错Unable to find RoutePredicateFactory with name 'Vip'。
原因 :类名未以RoutePredicateFactory结尾,Gateway无法从类名推断谓词名称。
解决 :将类名规范为{谓词名}RoutePredicateFactory的格式。
坑五:灰度路由order值配置错误
现象:灰度请求也被路由到了正常版本。
原因 :灰度路由的order值大于正常路由,导致正常路由先匹配。
解决 :灰度路由的order值应小于 正常路由。order越小优先级越高,默认值为0。
七、课后作业
作业一 :配置三条路由规则:/api/user/**路由到service-user,/api/order/**路由到service-order,/api/product/**路由到service-product。验证通过网关访问三个服务的接口。
作业二 :配置一条灰度路由,携带X-Gray-Version: v2 Header的请求路由到service-user-v2,其他请求路由到service-user-v1。使用curl验证两条路由的匹配结果。
作业三 :配置Weight权重路由,将service-user的95%流量路由到v1实例,5%路由到v2实例。通过多次调用观察流量分布。
作业四(进阶) :实现一个自定义谓词工厂TimeBetweenRoutePredicateFactory,支持配置时间段(如09:00-18:00),只有当前时间在该时间段内的请求才路由。在秒杀场景中使用该谓词。
八、下节预告
第19课将进入Gateway过滤器、全局拦截、请求响应统一处理。内容包括局部过滤器与全局过滤器的区别、执行顺序控制、跨域统一配置、请求参数校验、响应结果统一封装、异常统一拦截和日志全局打印。本课完成了路由规则的深度实战,路由决定了"请求去哪里",第19课的过滤器将决定"请求经过网关时做什么"------鉴权、日志、参数修改、响应增强,这些跨切面关注点都将在过滤器中实现。
🔗《最新版 SpringCloud 2025 从入门到实战》系列课程导航
第一部分:微服务前置基础 & 新版环境搭建(第1-5课)
第二部分:注册中心核心(Nacos 最新版)(第6-9课)
第三部分:配置中心核心(Nacos配置中心)(第10-12课)
第四部分:服务通信核心(OpenFeign + LoadBalancer)(第13-16课)
第五部分:网关核心(SpringCloud Gateway 新版)(第17-20课)
第六部分:熔断、限流、降级(Sentinel 新版)(第21-24课)
第七部分:微服务监控、链路追踪、日志体系(第25-28课)
第八部分:微服务高阶特性 & 分布式核心能力(第29-31课)
第九部分:企业级完整项目实战 & 架构复盘(第32-35课)