Spring Cloud Gateway:微服务流量的"中央调度官"
Java Web 微服务系列 · 第 6 篇 · Spring Cloud Gateway 阅读时长:约 26 分钟 本文写于 2026 年 6 月
引子:一次失败的发布让我们重新认识网关
2024 年下半年,我所在的团队做了一次"看似无害"的微服务重构——把原本单体应用里的 4 个核心业务模块拆成独立的 Spring Boot 服务,部署到 K8s 集群。架构图画得漂亮,CI/CD 流水线拉通,灰度发布、回滚机制一应俱全。
上线第一周就出事了。
凌晨 3 点,监控告警群炸了:所有下游服务的连接数(connection count)瞬间打满。我们 4 个服务,每个 50 个 Pod,一共有 200 个 Pod 收到了 20 倍的正常流量。日志翻出来一看——有个调用方在重试机制里写错了,所有失败的请求都被无限重试,而且重试时没有回退到服务名,而是打到了具体 Pod IP。
更糟糕的是:我们在网关层只做了"路径转发",没有任何限流、熔断、重试隔离。结果 200 个 Pod 直接雪崩,全站不可用 23 分钟。
事后复盘,CTO 在会上问了一个让我记忆深刻的问题:
“我们的网关到底在做什么?”
我答不上来。
那天晚上我回家翻 Spring Cloud Gateway 官方文档,从头读到尾。我意识到我们之前对网关的理解是错的——网关不是"路径转发器",网关是"微服务的中央调度官"。它该做的事情至少包括:统一鉴权、流量限流、熔断降级、灰度发布、日志追踪、监控告警。
第二天开始动手把网关从"路径转发器"升级成"流量调度官"——限流、熔断、灰度、鉴权、日志、监控一应俱全。这次我把它整理成一篇博客,从技术选型到核心类,从常用模块到实战配置,一次讲透。
下面是我踩过的所有坑。
那天之后我成了团队里的"网关布道师",每次新项目立项都先过网关设计。我意识到:网关不是"装上去就行了"的基础设施,是要持续投入运维的核心组件。规则、路由、限流、熔断,都要随业务演进动态调整——网关是活的系统,不是死的配置。
一、技术选型:为什么是 Spring Cloud Gateway
1.1 答案(拿分版)
微服务网关的选型,核心是看四件事:性能、协议支持、生态集成、团队熟悉度。 在 Java 技术栈里,Spring Cloud Gateway 是当下最优解——它基于 Reactor Netty 实现响应式编程,性能是 Zuul 1.x 的 1.6 倍;深度集成 Spring Cloud 生态(Nacos / Sentinel / Sleuth / Config 都能无缝对接);Java 团队几乎零学习成本,会写 Spring Boot 就上手。
1.2 横向对比:六大网关候选
| 网关 | 编程模型 | 性能 | 协议支持 | 生态 | 适用场景 |
|---|---|---|---|---|---|
| Spring Cloud Gateway | Reactor(响应式) | ★★★★★ | HTTP/HTTPS/WebSocket/gRPC | Spring 全家桶 | Java 微服务首选 |
| Zuul 1.x | Servlet(阻塞) | ★★★ | HTTP | Netflix OSS | 维护期,不推荐新项目 |
| Zuul 2.x | Netty(异步) | ★★★★ | HTTP | Netflix OSS | 文档少,Spring 集成弱 |
| Nginx + OpenResty | Lua/事件循环 | ★★★★★ | HTTP/TCP/UDP | 第三方模块 | 边缘网关 / 静态资源 |
| Kong | OpenResty + Lua | ★★★★★ | HTTP/gRPC | 插件生态 | 多语言混合架构 |
| APISIX | OpenResty + Lua | ★★★★★ | HTTP/gRPC/物联网 | Apache 顶级 | 云原生 / 多协议 |
结论:
- 纯 Java 微服务 → Spring Cloud Gateway(生态、性能、团队成本最优)
- 多语言混合(Java + Go + Python)→ Kong 或 APISIX(中立网关,插件丰富)
- 边缘入口(SSL 卸载、静态资源、CDN 协同)→ Nginx / OpenResty
- 遗留 Zuul 1.x → 升级到 Spring Cloud Gateway
1.3 Zuul → Gateway:Spring 为何换帅
2018 年 Netflix 宣布 Zuul 1.x 进入维护期,Spring Cloud 团队开始自研网关。核心原因有三点:
- 编程模型代际差:Zuul 1.x 基于 Servlet,每请求一线程,并发 1000 就要 1000 个线程,线程上下文切换开销巨大。Spring Cloud Gateway 基于 Reactor Netty,少量线程通过事件循环处理数万并发。
- 生态集成:Zuul 是 Netflix OSS 的一员,和 Spring Cloud 其他组件(Nacos / Sentinel / Config)整合需要胶水代码。Spring Cloud Gateway 是 Spring 亲儿子,开箱即用。
- 动态路由:Zuul 改路由要重启,Spring Cloud Gateway 支持运行时动态刷新(结合 Nacos)。
时间线:
| |
💡 原理:响应式 vs 阻塞模型
Zuul 1.x 基于 Servlet,每个请求独占一个线程。并发 1000 请求 = 1000 个线程,每个线程默认占 1MB 栈空间,1GB 内存被线程栈吃光。
Spring Cloud Gateway 基于 Reactor Netty,少量线程(默认 = CPU 核数 × 2)通过事件循环处理数万并发连接。单线程可处理 10000+ 并发,内存占用降一个数量级。
类比:阻塞模型 = 1 个服务员服务 1 桌客人;响应式 = 1 个服务员服务 N 桌客人(客人点完单他就去服务下一桌)。
1.4 Spring Cloud Gateway 的三大核心特性
- Route(路由):定义"什么请求 → 转发到哪"
- Predicate(断言):判断"这个请求匹不匹配这条路由"
- Filter(过滤器):在转发前后做"鉴权、限流、修改请求/响应"
三剑客的关系:Predicate 决定请求走哪条路由,Filter 决定请求在路由上做什么处理。
1.5 一个反直觉的事实:网关不是越复杂越好
很多团队第一次上 Gateway 容易"过度设计"——把所有鉴权、限流、灰度、监控全堆在 Gateway,结果 Gateway 成了新的单点瓶颈。
正确分层:
| 层 | 关注点 | 例子 |
|---|---|---|
| 边缘网关(Nginx) | SSL 卸载、CC 攻击、静态资源 | 100 万 QPS 也能扛 |
| 业务网关(Spring Cloud Gateway) | 鉴权、限流、路由 | 5 万 QPS 以内 |
| 业务服务 | 业务逻辑 | 1 万 QPS 以内 |
| 数据层 | 读写分离、分库分表 | — |
经验法则:Gateway 只做"横向能力"(鉴权、限流、灰度),不做"业务逻辑"(订单处理、用户管理)。业务逻辑下沉到下游服务,Gateway 保持轻量。
📌 实践:什么时候用 Spring Cloud Gateway?
- ✅ Java 微服务架构,服务数 ≥ 5 个
- ✅ 需要 统一鉴权 / 限流 / 灰度
- ✅ 需要 WebSocket / gRPC 协议透传
- ✅ 团队熟悉 Spring 生态
- ❌ 单一服务、单一入口 → 上 Nginx 就够了
- ❌ 多语言架构 → 上 Kong / APISIX
二、核心类:把"三剑客"扒到底层
2.1 答案(拿分版)
Spring Cloud Gateway 的内核只有三个核心接口:RouteLocator、Predicate、GatewayFilter。 所有高级特性(动态路由、限流、熔断)都是在这三个接口上的实现。理解了这三个接口,就理解了 Gateway 80% 的设计思想。剩下的 20% 是 RouteDefinitionLocator(路由定义定位器),用于动态路由场景。
2.2 三大核心接口
2.2.1 Route —— 路由定义
| |
关键字段:
id:路由唯一标识uri:目标地址(http://固定地址 /lb://service-name服务发现 /ws://WebSocket)predicate:匹配条件(注意是AsyncPredicate不是Predicate——支持异步匹配)filters:过滤器链
2.2.2 Predicate —— 断言匹配
Gateway 内置 11 个 Predicate 工厂(PathRoutePredicateFactory、MethodRoutePredicateFactory 等),全部实现 RoutePredicateFactory<C> 接口。源码在 org.springframework.cloud.gateway.handler.predicate 包。
| |
谓词的本质:返回一个 Predicate<ServerWebExchange>,对每个请求做 test() 判断,true → 命中路由。
为什么有"工厂"模式?因为每个 Predicate 需要带配置参数(如 Path=/api/order/** 里的路径)。工厂模式让"配置类 + 应用逻辑"解耦。
2.2.3 GatewayFilter —— 过滤器
| |
两种过滤器:
GatewayFilterFactory:路由级别的过滤器(写在 yml 的filters下,只对当前路由生效)GlobalFilter:全局过滤器(实现GlobalFilter接口,对所有路由生效)
执行顺序:
| |
chain.filter(exchange) 之前的代码 = pre-filter(请求处理前)
chain.filter(exchange) 之后的代码 = post-filter(响应处理后)
2.3 路由定位器:RouteDefinitionLocator 全家桶
| |
4 个核心实现(用于动态路由):
| 实现类 | 作用 | 场景 |
|---|---|---|
InMemoryRouteDefinitionRepository | 内存存储 | 默认实现,重启丢路由 |
PropertiesRouteDefinitionLocator | 读取 application.yml | 静态路由 |
DiscoveryClientRouteDefinitionLocator | 从注册中心读取 | 集成 Nacos / Eureka |
NacosRouteDefinitionRepository | 自定义 写 Nacos 持久化 | 生产推荐:动态路由 |
RouteDefinition → Route 的转换由 RouteDefinitionRouteLocator 完成。这条转换链是动态路由的核心——只要能拉取到 RouteDefinition,Gateway 就能转成 Route 生效。
💡 原理:动态路由的关键
Spring Cloud Gateway 启动时通过
RouteDefinitionRouteLocator把RouteDefinition转成Route对象。动态路由的本质是定时从外部存储(DB / Nacos / Redis)拉取RouteDefinition列表,刷新内存中的路由缓存。这就是为什么生产环境一定要用NacosRouteDefinitionRepository而不是 yml。
2.4 三个核心接口的协作流程
| |
关键设计:响应式全链路。从 Predicate 到 Filter 到转发,全程 Mono/Flux,没有任何阻塞调用。
2.5 高级接口:GatewayFilterFactory 的扩展点
AbstractGatewayFilterFactory<C> 是所有内置 Filter 的父类。自定义 Filter 只需要继承它:
| |
使用方式:
| |
🎯 避坑:自定义 Filter 时的 3 个易错点
- 不调用
chain.filter(exchange)→ 请求卡住,超时- 修改
ServerHttpRequest后没mutate()→ 改了原对象(ServerHttpRequest不可变)- 在 Filter 里写阻塞代码 → 整个事件循环卡死
2.6 Route 的 order 字段:路由优先级
Route 还有一个常被忽略的字段 order,控制多条路由同时匹配时哪条优先:
| |
执行顺序:v2_gray 优先匹配(order=0),命中灰度 Header 走 v2;其他走 v1(order=100)。
生产经验:灰度路由 order 设小,兜底路由 order 设大;两者差值至少 50,方便后续插入中间版本。
2.7 Predicate 短路优化
Gateway 的 Predicate 是短路求值——第一个不满足就不继续。比如:
| |
调优技巧:便宜的断言放前面,贵的(如正则)放后面。Path 是最快的(字符串比较),Header 需要正则解析,最慢。
💡 原理:Predicate 的执行顺序
Gateway 内部把
Route的所有 Predicate 包装成Predicate<ServerWebExchange>链。命中顺序是按 yml 配置顺序短路求值——所以你写的第一个 Predicate 一定先执行。
三、常用模块:11 个 Predicate + 30+ Filter 一网打尽
3.1 答案(拿分版)
Gateway 的"常用模块"分四类:路由断言、过滤器工厂、全局过滤器、生态集成。 生产环境必装的是 Path + Method + Header 三个断言、StripPrefix + AddRequestHeader 两个过滤器、以及一个 GlobalFilter 做统一鉴权。掌握这 6 个配置项,就能覆盖 80% 的业务场景。剩下的 20% 来自 Sentinel 限流、Hystrix/Resilience4j 熔断、Prometheus 监控这三个生态集成。
3.2 11 个内置 Predicate 工厂
| Predicate | 用途 | 示例 |
|---|---|---|
Path | 路径匹配 | Path=/api/order/** |
Method | HTTP 方法 | Method=GET,POST |
Header | 请求头 | Header=X-Token, \d+ |
Query | 查询参数 | Query=token, \w+ |
Host | 域名 | Host=**.example.com |
Cookie | Cookie | Cookie=session, \w+ |
After / Before / Between | 时间窗口 | After=2026-01-01T00:00:00+08:00 |
RemoteAddr | IP 段 | RemoteAddr=192.168.1.0/24 |
Weight | 权重路由 | Weight=order-svc, 80 |
CloudFoundryRoute | CF 平台 | (云平台专用) |
Predicate 组合是 AND 关系——一条路由的所有 Predicate 都为 true,请求才命中。
示例:组合 Predicate
| |
含义:/api/order/** 的 GET/POST 请求,必须带 X-Tenant 头(字母数字下划线),从 2026-01-01 起,且来自内网 IP。
3.3 30+ 内置 GatewayFilter 工厂
按功能分 6 大类:
(1)路径处理
| Filter | 作用 | 示例 |
|---|---|---|
StripPrefix=1 | 去掉路径前缀 1 段 | /api/order/list → /list |
PrefixPath=/api | 加前缀 | /user/list → /api/user/list |
SetPath=/order/{segment} | 重写路径 | /api/o/123 → /order/123 |
(2)请求头 / 响应头
| Filter | 作用 |
|---|---|
AddRequestHeader=X-Source, gateway | 加请求头 |
AddResponseHeader=X-Trace-Id, ... | 加响应头 |
RemoveRequestHeader=Cookie | 删请求头 |
(3)参数处理
| Filter | 作用 |
|---|---|
AddRequestParameter=source, web | 加查询参数 |
SetQueryString=foo=bar | 重写查询串 |
(4)重定向 / 状态码
| Filter | 作用 |
|---|---|
RedirectTo=302, https://... | 重定向 |
SetStatus=401 | 改状态码 |
(5)限流 / 熔断(需额外依赖)
| Filter | 作用 |
|---|---|
RequestRateLimiter | Redis 令牌桶限流 |
CircuitBreaker | 集成 Hystrix / Sentinel / Resilience4j |
(6)其他
| Filter | 作用 |
|---|---|
Retry=3 | 重试 3 次 |
Hystrix | 熔断(已不推荐) |
SaveSession | WebFlux Session |
SecureHeaders | 安全响应头 |
PreserveHostHeader | 保留原始 Host |
DedupeResponseHeader | 去重响应头 |
3.4 GlobalFilter:4 个最常用实现
GlobalFilter 对所有路由生效,用 @Component 注册即可。
| GlobalFilter | 作用 | 适用场景 |
|---|---|---|
| 自定义鉴权 | 校验 JWT / Token | 所有需要登录的接口 |
| 统一日志 | 记录 request/response | 全链路追踪 |
| 跨域处理 | CORS 配置 | 前后端分离 |
| 限流 | Redis 令牌桶 | 防止突发流量 |
🎯 避坑:GlobalFilter 注册顺序
@Order数字越小,越早执行。鉴权 GlobalFilter 必须在限流/日志之前,否则会先限流再鉴权,导致未鉴权用户触发限流统计的脏数据。推荐顺序:
SecurityFilter鉴权(@Order(-100))RequestLogFilter日志(@Order(-50))RateLimitFilter限流(@Order(0))- 业务 GlobalFilter
3.5 生态集成:从单网关到微服务流量平台
| |
生产推荐组合:
- 服务发现:Nacos(性能优于 Eureka,自带配置中心)
- 限流熔断:Sentinel(阿里出品,规则可动态推送,优于 Hystrix)
- 链路追踪:Micrometer Tracing + Zipkin(Sleuth 已弃用)
- 配置中心:Nacos(路由规则 / 限流规则 持久化)
- 监控告警:Actuator + Prometheus + Grafana
📌 实践:为什么 Sentinel 替代 Hystrix?
Hystrix 2018 年宣布停更,官方推荐用 Resilience4j 或 Sentinel。Sentinel 的核心优势是规则可动态推送——网关限流阈值调整不用重启服务,Nacos 一推即生效。Hystrix 只能改配置重启。
此外 Sentinel 还有:
- 流量染色:按用户/接口打标,灰度路由
- 系统自适应限流:根据 CPU / Load 自动降级
- 热点参数限流:识别高频参数(如秒杀商品 ID)单独限流
3.6 11 个 Predicate 详细使用场景
生产中最常用的 5 个断言(覆盖 90% 场景):
| Predicate | 真实场景 | 示例 |
|---|---|---|
Path | 路由分流 | /api/order/** → order-svc |
Method | 读写分离 | Method=GET,POST(部分服务只接 GET) |
Header | 灰度发布 | Header=X-Gray-Tag, beta |
Query | 鉴权 token 透传 | Query=token, \w+ |
RemoteAddr | 内网/外网分流 | RemoteAddr=10.0.0.0/8(仅内网) |
不常用但有特殊价值的 3 个断言:
| Predicate | 场景 |
|---|---|
After / Before | 限时活动(“双 11 凌晨 0 点开始”) |
Cookie | 灰度按用户固定分组(带 cookie 不变) |
Weight | A/B 测试(按流量比例分流) |
示例:限时活动 Predicate
| |
3.7 GatewayFilter 工厂的"链式调用"模式
Gateway 的多个 Filter 按 yml 顺序组成链式调用。重要:每个 Filter 的 chain.filter(exchange) 之前是 pre、之后是 post:
| |
执行流程:
| |
调优原则:pre 阶段做"请求处理"(鉴权、加头、限流);post 阶段做"响应处理"(加响应头、统计耗时)。
🎯 避坑:Filter 顺序的 2 个常见错误
StripPrefix放在AddRequestHeader之后 → AddRequestHeader 引用了 strip 前的路径,调试时找不到头在哪加的Retry放在RequestRateLimiter之前 → 限流计数时 Retry 重试的请求会算多次,限流阈值要相应调大
四、实战:从 yml 到 Java DSL,从单体 Filter 到灰度发布
4.1 答案(拿分版)
Gateway 的实战分四步:yml 写简单路由 → Java DSL 写复杂路由 → 自定义 GlobalFilter 做鉴权 → 加灰度发布 Header 走灰度。 掌握这 4 步,从 demo 到生产只用 2 小时。核心是:路由配置用 yml 起步、业务逻辑用 GlobalFilter 注入、动态配置用 Nacos 持久化。
4.2 第一步:yml 简单路由
| |
含义:/api/order/** 的 GET/POST 请求,去掉前 2 段路径(/api/order),转发到 order-svc 服务,并加 X-Source: gateway 请求头。
lb:// 前缀:表示走服务发现(LoadBalancer),从 Nacos 拉取 order-svc 的实例列表,做负载均衡。
4.3 第二步:Java DSL 编程式路由
复杂路由用 yml 写不直观,改用 Java DSL:
| |
Java DSL 的优势:可加判断逻辑(从 DB / 配置中心读路由参数),适合动态路由场景。
实战场景:根据租户 ID 决定转发到不同集群。
| |
4.4 第三步:自定义 GlobalFilter(登录校验示例)
| |
关键点:
exchange.mutate()修改后必须chain.filter()透传- 状态码/响应体在 GlobalFilter 里直接
writeWith即可中断链路 @Order(1)数字越小越早执行,鉴权必须最先
4.5 第四步:灰度发布(基于 Header 权重路由)
| |
升级灰度:v1 占 90% 流量,v2 占 10%。逐步调高 v2 权重到 100%,灰度完成。
更精细的灰度:基于 Header 指定版本
| |
测试人员带 X-Gray-Tag: beta 头走 v2,普通用户走 v1。
🛑 误区:灰度发布的 3 个常见错误
- 用 Cookie / Session 做灰度 → 用户关浏览器重新打开就走错版本
- 灰度路由不带版本号 → 紧急回滚时不知道切哪个
- 灰度期间不监控错误率 → 上线 5% 流量已经报错,迟迟没发现
正确做法:用
Header=X-Gray-Tag, beta做灰度,灰度路由命名带_gray后缀,监控 5xx 错误率超过阈值自动回滚。
4.6 第五步:全局异常处理(ErrorWebExceptionHandler)
Gateway 抛异常时(如路由找不到、限流拒绝),默认返回 500 + 空白页面。生产环境必须自定义错误响应:
| |
效果:所有异常返回 JSON {code, msg, path},前端可解析。
4.7 自定义 Predicate 实战(按租户分流)
内置 Predicate 不够用时,自定义 Predicate 是终极武器。实现 RoutePredicateFactory<MyConfig> 接口:
| |
使用方式(yml):
| |
实战场景:多租户 SaaS 平台,按租户 ID 决定请求走哪个集群。
4.8 网关压力测试(用 wrk)
生产前必跑压力测试。wrk 是 Linux 高性能 HTTP 压测工具:
| |
关键指标:
| 指标 | 含义 | 健康阈值 |
|---|---|---|
Latency Distribution 50% | 中位数延迟 | < 50ms |
Latency Distribution 99% | 99 分位延迟 | < 200ms |
Requests/sec | QPS | ≥ 预期峰值 1.5 倍 |
Socket errors | 套接字错误 | 0 |
生产经验:网关压测必须用真实下游服务 mock(如 wiremock),不能直接压空 Gateway——否则延迟全在下游。
📌 实践:网关压测 3 个关键点
- 冷启动要算——前 1000 个请求延迟偏高(Netty 启动、类加载),生产要预热
- 限流要测——故意打超限流阈值,看 Gateway 是否正确返回 429
- 熔断要测——下游 mock 故意 5xx,看 Gateway 是否触发熔断
阿里云 AHAS 提供了专业的网关压测服务(
ahas-console),生产级项目推荐。
五、配置:从 CORS 到限流,从超时到监控
5.1 答案(拿分版)
Gateway 的"必配"配置有 5 项:CORS 跨域、连接超时、限流、熔断、监控。 漏配任何一项都可能引发生产事故——CORS 不配,前端调不通;超时不配,慢调用拖垮网关;限流不配,雪崩;熔断不配,单服务故障扩散全站;监控不配,出了事不知道。
5.2 CORS 跨域完整配置
| |
🎯 避坑:
allowCredentials: true+allowedOrigins: *会报错必须改成
allowedOriginPatterns: "*"(Spring Boot 2.4+ 才支持)。这是初学者最常踩的坑。
5.3 超时与重试
| |
生产经验:
connect-timeout: 1s、response-timeout: 5s是大多数场景的安全值- 重试只对幂等接口开(GET),POST 重试可能产生重复订单
- 重试配合
backoff指数退避,避免雪崩
5.4 限流(内置 Redis 令牌桶)
| |
KeyResolver 实现(按用户限流):
| |
📌 实践:限流算法选型
算法 优点 缺点 适用 令牌桶 平滑限流、允许突发 配置稍复杂 通用首选 漏桶 强制匀速 突发流量被截断 严格流量整形 滑动窗口 精确控制时间窗 内存开销大 短时间窗口限流 生产推荐令牌桶(
replenishRate=平均QPS, burstCapacity=峰值QPS)。
5.5 熔断(集成 Sentinel)
Sentinel 是阿里出品的流量治理组件,比 Hystrix 强在规则可动态推送。
| |
Sentinel 控制台配置:
- 资源名:
order-svc:/api/order/list - 熔断策略:慢调用比例(RT > 1s 的请求占比 > 50% 触发熔断)
- 熔断时长:10s
- 半开恢复:探测请求数 5
5.6 监控(Actuator + Prometheus)
| |
Gateway 关键指标:
| 指标 | 含义 |
|---|---|
gateway.requests | 总请求数(带 routeId 标签) |
gateway.route.predicate.matched | 路由命中数 |
http.client.requests | 下游 HTTP 调用(带 uri, status, outcome) |
jvm.memory.used | JVM 内存使用 |
Grafana 仪表盘推荐:
- Spring Cloud Gateway 官方仪表盘 ID: 11591
- 自定义 4 个核心面板:QPS、P99 延迟、5xx 错误率、限流次数
5.7 动态路由(生产推荐)
痛点:yml 路由改一次,要重启网关。10 个路由的微服务集群,每次业务变更都要重启网关 = 不可接受。
解决方案:自定义 RouteDefinitionRepository,从 Nacos 读取路由。
| |
Nacos 控制台配置:
- Data ID:
gateway-routes - Group:
DEFAULT_GROUP - 配置内容:JSON 格式的
RouteDefinition列表
改路由:在 Nacos 控制台改 JSON,网关 5 秒内自动刷新,无需重启。
🛑 误区:动态路由的 3 个坑
- 不加缓存 → 每次请求都读 Nacos,性能崩盘。必须本地缓存 + 监听 Nacos 变更事件
- 路由变更不通知 → 改完 Nacos 没刷内存。必须监听
NacosConfigService的addListener- 动态路由不校验 → 写错的 JSON 让 Gateway 启动失败。必须有合法 yml 兜底,动态路由加载失败时回退
5.8 完整生产配置模板
| |
5.9 网关安全配置清单
生产环境必配 6 项:
| 配置 | 作用 | 推荐值 |
|---|---|---|
X-Frame-Options | 防点击劫持 | DENY |
X-Content-Type-Options | 防 MIME 嗅探 | nosniff |
Strict-Transport-Security | 强制 HTTPS | max-age=31536000 |
Content-Security-Policy | 防 XSS | default-src 'self' |
Referrer-Policy | 控制 Referer | no-referrer |
X-XSS-Protection | 浏览器 XSS 防护 | 1; mode=block |
Gateway 自带 SecureHeaders Filter,默认开启这 6 个安全头。禁用方式(不推荐):
| |
5.10 网关高可用部署
单点网关是灾难——网关挂了,所有流量进不来。生产必做:网关至少 2 个实例 + 负载均衡 + 健康检查。
架构:
| |
K8s 部署(推荐):
| |
健康检查:Spring Cloud Gateway 默认带 /actuator/health,K8s 探针每 10s 查一次,不健康实例自动从 Service 摘除。
总结:一张图 + 一句话
一张图:Gateway 在微服务架构中的位置
| |
一句话总结
Spring Cloud Gateway = “路由 + 断言 + 过滤器” 三个核心接口的精妙组合。用对这三个接口,再配上限流、熔断、监控,就能在 Java 微服务架构里撑起"流量中央调度官"的角色。
选型决策树
| |
系列下一篇预告
下一篇会写 Nacos 配置中心 + 注册中心——Gateway 的动态路由、限流规则都依赖它。
速查表:5 大场景的核心配置
| 场景 | 核心配置 | 文件位置 |
|---|---|---|
| 统一鉴权 | GlobalFilter + JWT | AuthGlobalFilter.java |
| 限流 | RequestRateLimiter + Redis | application.yml |
| 熔断 | Sentinel 资源规则 | Sentinel 控制台 |
| 灰度发布 | Header=X-Gray-Tag + Weight | application.yml |
| 动态路由 | Nacos + 自定义 RouteDefinitionRepository | Nacos 控制台 |
生产清单:把这 5 件事都做了,网关才真的"中央调度官"——缺一项都是假网关。
参考资料
- Spring Cloud Gateway 官方文档
- Reactor Netty 官方文档
- Sentinel 官方文档
- Spring Cloud Alibaba GitHub
- Nacos 官方文档
- 《Spring 微服务实战》(John Carnell 著)
💡 延伸学习:响应式编程为什么快?
Spring Cloud Gateway 基于 Reactor Netty,本质是 NIO + 事件循环。
- 阻塞模型(Zuul 1.x):每请求一线程,线程数 = 并发数。1000 并发 = 1000 线程,每个线程默认占 1MB 栈空间 = 1GB 内存
- 响应式模型(Reactor):少量线程(= CPU 核数 × 2)通过事件循环处理数万连接,单线程可处理 10000+ 并发
- 类比:阻塞模型 = 1 个服务员服务 1 桌客人;响应式 = 1 个服务员服务 N 桌客人(客人点完单他就去服务下一桌)
缺点是调试复杂——堆栈不直观、阻塞代码会让整个事件循环卡死。生产中禁止在 Gateway 里写阻塞代码(JDBC / 同步 HTTP /
Thread.sleep)。
