SpringCloudAlibaba_Gateway详解
Spring Cloud Alibaba:Gateway 详解
课程位置:第四阶段「微服务项目 + AI 应用」第 4 课
前置知识:微服务体系架构、Nacos、Feign、LoadBalancer、Sentinel、Spring Boot 3
本课主题:Spring Cloud Gateway
后续课程:若依 Cloud 框架部署与代码修改器使用
学习目标:从“前端直接访问多个微服务”的问题开始,理解 API Gateway 的作用,掌握 Gateway Server WebFlux、Route、Predicate、GatewayFilter、GlobalFilter、lb://、Nacos 服务发现、路径改写、CORS、统一鉴权、JWT、白名单、Filter 顺序、超时、限流、Actuator 路由查看以及 Gateway + Sentinel 的基本配合。
一、先回顾我们现在的微服务结构
前面我们已经有:
user-service
order-service
并且:
order-service
↓ Feign
user-service
服务注册到:
Nacos
Sentinel:
保护服务内部资源和远程调用
现在还有一个问题:
前端到底访问谁?
二、如果没有 Gateway
Vue 前端可能需要记:
http://localhost:8081/users/**
http://localhost:8082/orders/**
http://localhost:8083/travel/**
http://localhost:8084/search/**
http://localhost:8085/ai/**
这会越来越乱。
三、前端直接访问微服务有什么问题
第一:
前端必须知道每个服务地址
第二:
服务端口变化
前端也可能跟着改
第三:
每个服务都要重复处理跨域
第四:
每个服务都可能重复做 Token 校验
第五:
内部服务结构直接暴露给客户端
第六:
统一限流、日志、黑名单不好做
四、于是需要 API Gateway
Gateway 可以理解为:
微服务系统统一入口
结构变成:
Vue
↓
Gateway : 8080
├─ /api/users/** → user-service
├─ /api/orders/** → order-service
├─ /api/travel/** → travel-service
└─ /api/ai/** → ai-service
前端只需要知道:
Gateway 地址
五、Gateway 最核心职责
可以先记:
路由
过滤
统一入口
进一步包括:
统一鉴权
跨域
日志
限流
Header 处理
灰度路由
监控
六、Gateway 不应该干什么
Gateway 不应该变成:
超级业务服务
不要把:
订单金额计算
库存扣减
审批业务
用户积分计算
放进 Gateway。
七、正确职责边界
Gateway:
处理入口横切逻辑
业务服务:
处理真正业务
八、Gateway 和 Nginx 的关系
两者都可以:
反向代理
常见部署:
Internet
↓
Nginx
↓
Spring Cloud Gateway
↓
Microservices
九、Nginx 更擅长
TLS/HTTPS
静态资源
高性能反向代理
网络入口
基础负载均衡
十、Gateway 更擅长
Spring Cloud 服务发现
业务路由
Java 过滤器
统一认证上下文
与 Spring 生态集成
十一、这一课使用哪种 Gateway
Spring Cloud Gateway 现在有:
Server WebFlux
Server WebMVC
课程选择:
Spring Cloud Gateway Server WebFlux
这是传统 Spring Cloud 微服务项目中非常常见的一条路线。
十二、为什么要特别说 WebFlux
因为 Gateway Server WebFlux:
不是 Spring MVC Servlet 模型
它建立在:
Spring WebFlux
Project Reactor
Reactor Netty
之上。
十三、最容易踩的坑
不要在 Gateway WebFlux 模块里无脑加入:
spring-boot-starter-web
然后再混:
Tomcat
Servlet Filter
HttpServletRequest
十四、Gateway Server WebFlux 的运行时
官方明确说明:
依赖 Spring WebFlux
+
Reactor Netty
并且:
不运行在传统 Servlet Container 模式中
十五、所以 Gateway 模块要有“反应式思维”
你会看到:
Mono<Void>
而不是普通 Controller 常见:
void
String
AjaxResult
十六、版本变化:Starter 名称
Spring Cloud 2025.0.0 对 Gateway 模块命名做了调整。
课程当前基线:
Spring Cloud 2025.0.x
Spring Boot 3.5.x
Gateway 属于:
4.3.x
十七、新 Starter 名称
推荐:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>
spring-cloud-starter-gateway-server-webflux
</artifactId>
</dependency>
十八、旧教程可能看到
spring-cloud-starter-gateway
或者:
spring-cloud-starter-gateway-server
这些属于:
旧命名
十九、2025.0.x 为什么改名
为了明确区分:
Server / Proxy Exchange
WebFlux / WebMVC
新名字更清晰:
gateway-server-webflux
二十、配置前缀也发生变化
旧教程常见:
spring:
cloud:
gateway:
routes:
Spring Cloud 2025.0.x 新前缀:
spring:
cloud:
gateway:
server:
webflux:
routes:
二十一、这一点非常重要
这节课统一使用:
spring.cloud.gateway.server.webflux.*
避免继续写旧式:
spring.cloud.gateway.*
二十二、创建 gateway 模块
父工程现在:
spring-cloud-demo
├─ user-service
├─ order-service
└─ gateway
二十三、父 pom 加 module
<modules>
<module>user-service</module>
<module>order-service</module>
<module>gateway</module>
</modules>
二十四、gateway pom
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>
spring-cloud-starter-gateway-server-webflux
</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>
spring-cloud-starter-alibaba-nacos-discovery
</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>
spring-cloud-starter-loadbalancer
</artifactId>
</dependency>
</dependencies>
二十五、为什么 Gateway 也需要 Nacos
Gateway 的目标:
把请求转发给 user-service
它必须知道:
user-service 当前在哪台机器
所以:
Gateway 也是服务消费者
需要:
服务发现
二十六、Gateway application.yml
server:
port: 8080
spring:
application:
name: gateway
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848
二十七、启动后 Nacos
应该看到:
gateway
user-service
order-service
二十八、Route 是什么
Gateway 最核心概念:
Route
中文:
路由
二十九、一个 Route 包含什么
最重要:
id
uri
predicates
filters
三十、可以理解成
如果请求满足 predicates
↓
先经过 filters
↓
转发到 uri
三十一、第一条最简单路由
spring:
cloud:
gateway:
server:
webflux:
routes:
- id: user-service-route
uri: http://localhost:8081
predicates:
- Path=/users/**
三十二、这个路由什么意思
请求:
GET http://localhost:8080/users/1
匹配:
Path=/users/**
Gateway 转发:
http://localhost:8081/users/1
三十三、这只是第一步
目前:
uri 仍然写死 localhost:8081
我们已经学过:
这种方式不适合微服务
三十四、改成 lb://
spring:
cloud:
gateway:
server:
webflux:
routes:
- id: user-service-route
uri: lb://user-service
predicates:
- Path=/users/**
三十五、lb 是什么
lb
=
load balance
表示:
按照服务名
通过 LoadBalancer 找实例
三十六、完整过程
请求 /users/1
↓
Gateway 匹配 user-service-route
↓
看到 lb://user-service
↓
Nacos Discovery
↓
获取 user-service 实例
↓
ReactiveLoadBalancer
↓
选择一个实例
↓
HTTP 转发
三十七、如果 user-service 有两个实例
例如:
127.0.0.1:8081
127.0.0.1:8083
Gateway:
不需要写两条路由
仍然:
lb://user-service
LoadBalancer:
选择实例
三十八、找不到实例会怎样
Gateway WebFlux 默认:
返回 503
因为:
Service Unavailable
三十九、这类错误怎么排查
Nacos 中有没有服务
服务名是否一致
Namespace 是否一致
实例是否健康
LoadBalancer 依赖是否存在
四十、order-service 路由
spring:
cloud:
gateway:
server:
webflux:
routes:
- id: user-service-route
uri: lb://user-service
predicates:
- Path=/users/**
- id: order-service-route
uri: lb://order-service
predicates:
- Path=/orders/**
四十一、现在前端只访问 Gateway
用户:
GET localhost:8080/users/1
订单:
GET localhost:8080/orders/1001
前端:
不再关心 8081 / 8082
四十二、Predicate 是什么
Predicate:
断言
可以理解:
“什么请求应该匹配这条路由?”
四十三、最常用 Path Predicate
predicates:
- Path=/users/**
意思:
路径满足 /users/**
才进入这条 Route。
四十四、Path 通配符
/users/**
可以匹配:
/users/1
/users/list
/users/profile/avatar
四十五、Method Predicate
predicates:
- Path=/users/**
- Method=GET
同时要求:
路径匹配
AND
请求方法是 GET
四十六、多个 Predicate 默认关系
同一个 Route 中多个 Predicate:
必须全部满足
可以理解:
AND
四十七、Header Predicate
例如:
predicates:
- Header=X-Request-Type, internal
要求 Header:
X-Request-Type
匹配:
internal
四十八、Query Predicate
例如:
predicates:
- Query=source, app
只有:
?source=app
满足时匹配。
四十九、Host Predicate
例如:
predicates:
- Host=api.example.com
可以按域名:
选择路由
五十、Cookie Predicate
可以根据:
Cookie
进行匹配。
五十一、时间 Predicate
Gateway 还支持:
After
Before
Between
适合:
限时活动路由
五十二、RemoteAddr Predicate
可以根据:
来源 IP
判断。
五十三、为什么 Predicate 很强
Gateway 不只是:
URL → URL
它可以根据:
Path
Method
Header
Query
Host
IP
时间
决定:
请求去哪
五十四、不要过度设计 Predicate
普通业务项目:
Path
通常已经解决绝大多数路由。
复杂规则:
按业务需要添加
五十五、Filter 是什么
Gateway Filter:
过滤器
负责:
请求转发前后
修改请求/响应
五十六、Predicate 和 Filter 区别
Predicate
→ 要不要匹配这条路由
Filter
→ 匹配后要做什么处理
五十七、最常见 Filter:StripPrefix
假设前端统一:
/api/user/**
但是 user-service Controller 是:
/users/**
需要:
去掉一部分前缀
五十八、StripPrefix 原理
请求:
/api/users/1
配置:
filters:
- StripPrefix=1
去掉第一个 path segment:
/api
下游变:
/users/1
五十九、完整配置
spring:
cloud:
gateway:
server:
webflux:
routes:
- id: user-service-route
uri: lb://user-service
predicates:
- Path=/api/users/**
filters:
- StripPrefix=1
六十、请求过程
客户端:
/api/users/1
↓ Path 匹配
↓ StripPrefix=1
/users/1
↓ lb://user-service
user-service
六十一、StripPrefix=2
请求:
/api/v1/users/1
去掉:
/api
/v1
下游:
/users/1
六十二、不要 Strip 错了
如果 Provider 本身 Controller:
/api/users/1
你又:
StripPrefix=1
就可能:
404
六十三、Gateway 404 排查第一件事
写出:
客户端原始路径
↓
Predicate 匹配路径
↓
Filter 处理后路径
↓
Provider Controller 真正路径
四步对照。
六十四、RewritePath
如果不是简单去前缀,
可以:
重写路径
例如:
filters:
- RewritePath=/api/users/(?<segment>.*), /users/${segment}
六十五、RewritePath 比 StripPrefix 更灵活
但也:
更容易写错正则
简单场景:
优先 StripPrefix
六十六、PrefixPath
作用相反:
给下游路径增加前缀
请求:
/users/1
可以转成:
/api/users/1
六十七、AddRequestHeader
例如:
filters:
- AddRequestHeader=X-Gateway, cloud-demo
下游收到:
X-Gateway: cloud-demo
六十八、RemoveRequestHeader
可以删除:
某些客户端不该传给内部服务的 Header
这在:
安全设计
中很重要。
六十九、AddResponseHeader
Gateway 可以给响应加:
Header
例如:
X-Gateway-Version
七十、SetStatus
可以改变:
HTTP Status
七十一、RequestSize
可以限制:
请求体大小
例如上传入口:
防止超大请求
七十二、为什么 Gateway 很适合做请求体大小限制
因为:
越早拒绝
成本越低
不需要请求进入:
业务服务
才发现太大。
七十三、GatewayFilter 和 GlobalFilter
GatewayFilter:
只作用于某条 Route
GlobalFilter:
作用于所有匹配路由
七十四、什么时候用路由 Filter
例如:
只有文件服务
需要限制上传大小
使用:
Route Filter
七十五、什么时候用 GlobalFilter
例如:
统一日志
统一 Token 检查
TraceId
全局 Header
适合:
GlobalFilter
七十六、第一个 GlobalFilter
@Component
public class LogGlobalFilter
implements GlobalFilter, Ordered {
private static final Logger log =
LoggerFactory.getLogger(
LogGlobalFilter.class
);
@Override
public Mono<Void> filter(
ServerWebExchange exchange,
GatewayFilterChain chain
) {
String path =
exchange
.getRequest()
.getURI()
.getPath();
long start =
System.currentTimeMillis();
log.info(
"Gateway request start, path={}",
path
);
return chain
.filter(exchange)
.doFinally(signalType -> {
long cost =
System.currentTimeMillis()
- start;
log.info(
"Gateway request end, path={}, cost={}ms",
path,
cost
);
});
}
@Override
public int getOrder() {
return -100;
}
}
七十七、为什么返回 Mono
因为:
Gateway WebFlux
是反应式链路
请求处理:
异步非阻塞
七十八、最重要:不要在 GlobalFilter 里阻塞
危险:
Thread.sleep(5000);
或者:
大量阻塞式数据库访问
七十九、为什么
Gateway 使用:
Netty Event Loop
如果阻塞:
少量线程被长时间占用
会严重影响:
整个 Gateway 吞吐
八十、所以 Gateway 不适合做复杂 DB 权限查询
如果每一个请求:
Gateway 查 5 张 MySQL 表
设计通常:
过重
八十一、统一认证和完整业务授权要区分
Gateway 可以做:
Token 是否存在
Token 是否有效
基础身份解析
业务服务仍应该做:
具体资源权限
数据权限
业务授权
八十二、为什么不能只靠 Gateway 授权
内部服务可能:
被其他内部服务直接调用
而且:
业务权限离业务数据更近
八十三、所以推荐分层
Gateway
→ 身份认证、基础入口安全
业务服务
→ RBAC、数据权限、业务校验
八十四、JWT 统一认证基本流程
客户端登录
↓
拿到 JWT
↓
请求 Gateway
↓
Gateway 校验 JWT
↓
解析 userId
↓
转发内部服务
八十五、白名单
例如:
/login
/captcha
/public/**
这些:
不用登录
八十六、其他路径
必须有合法 Token
八十七、白名单配置
可以:
security:
ignore:
paths:
- /api/auth/login
- /api/auth/captcha
- /api/public/**
然后:
Gateway Filter 读取
八十八、不要硬编码几十个 if
错误:
if (
path.equals("/login")
|| path.equals("/captcha")
|| ...
)
推荐:
配置化白名单
八十九、JWT Filter 逻辑示意
@Component
public class AuthGlobalFilter
implements GlobalFilter, Ordered {
private final TokenService tokenService;
public AuthGlobalFilter(
TokenService tokenService
) {
this.tokenService =
tokenService;
}
@Override
public Mono<Void> filter(
ServerWebExchange exchange,
GatewayFilterChain chain
) {
ServerHttpRequest request =
exchange.getRequest();
String path =
request
.getURI()
.getPath();
if (isWhiteList(path)) {
return chain.filter(exchange);
}
String token =
request
.getHeaders()
.getFirst(
HttpHeaders.AUTHORIZATION
);
if (!tokenService.isValid(token)) {
return unauthorized(exchange);
}
Long userId =
tokenService.getUserId(token);
ServerHttpRequest newRequest =
request
.mutate()
.headers(headers -> {
headers.remove(
"X-User-Id"
);
headers.add(
"X-User-Id",
String.valueOf(userId)
);
})
.build();
ServerWebExchange newExchange =
exchange
.mutate()
.request(newRequest)
.build();
return chain.filter(newExchange);
}
@Override
public int getOrder() {
return -200;
}
}
九十、为什么先 remove X-User-Id
这是非常重要的安全点。
客户端可能自己发送:
X-User-Id: 1
如果 Gateway:
直接相信
就可能:
伪造身份
九十一、正确
删除客户端传来的内部身份 Header
↓
Gateway 根据合法 Token 重新生成
九十二、但下游能不能绝对相信 X-User-Id
只有在:
内部网络边界可靠
并且下游不能被公网直接访问
的情况下,
才能把 Gateway 注入 Header:
作为可信上下文的一部分
九十三、生产更严谨的方式
还可能:
内部签名
mTLS
OAuth2 Resource Server
Token Relay
Service Identity
当前课程先掌握:
不要信任客户端伪造内部 Header
九十四、Gateway 官方也支持 Spring Security
Gateway Server WebFlux 可以配合:
Spring Security
但是注意:
是 WebFlux 安全模型
九十五、WebFlux Security 用什么
常见:
SecurityWebFilterChain
ServerHttpSecurity
不是传统 Servlet:
SecurityFilterChain + HttpSecurity
那一套直接照搬。
九十六、为什么容易混
你前面 Spring Boot 普通后台:
Spring MVC
Gateway:
Spring WebFlux
两个:
Web 技术栈不同
九十七、不要在 Gateway 里使用 HttpServletRequest
WebFlux 常用:
ServerHttpRequest
ServerHttpResponse
ServerWebExchange
九十八、ServerWebExchange 可以理解成
一次 Gateway 请求上下文
里面有:
Request
Response
Attributes
九十九、Filter 顺序
GlobalFilter 可以实现:
Ordered
返回:
getOrder()
决定顺序。
一百、数字越小
通常:
优先级越高
例如:
-200
比:
-100
更早进入 pre 阶段。
一百零一、Gateway Filter 有 pre 和 post
请求:
进入
执行:
pre
转发下游。
响应回来:
post
一百零二、顺序非常有意思
如果:
Filter A order=-100
Filter B order=0
pre:
A
↓
B
post:
B
↓
A
一百零三、为什么
类似:
方法调用栈
外层先进入:
最后退出
一百零四、过滤器顺序示意
A pre
↓
B pre
↓
Route
↓
B post
↓
A post
一百零五、为什么认证 Filter 要比较早
因为未登录请求:
应该尽早拒绝
不要:
先做大量无意义工作
一百零六、但顺序不能只靠“写个 -99999”
企业项目:
所有 GlobalFilter 顺序应该统一规划
例如:
TraceId -300
Auth -200
Logging -100
只是示意。
一百零七、跨域 CORS
前端:
http://localhost:5173
Gateway:
http://localhost:8080
协议/域名/端口不同:
就可能跨域
一百零八、为什么 Gateway 适合统一 CORS
因为:
所有前端请求都先经过 Gateway
可以:
集中处理
一百零九、Spring Cloud 2025.0.x CORS 配置
spring:
cloud:
gateway:
server:
webflux:
globalcors:
add-to-simple-url-handler-mapping: true
cors-configurations:
'[/**]':
allowedOrigins:
- "http://localhost:5173"
allowedMethods:
- GET
- POST
- PUT
- DELETE
- OPTIONS
allowedHeaders:
- "*"
allowCredentials: true
maxAge: 3600
一百一十、add-to-simple-url-handler-mapping
这个配置对:
OPTIONS 预检请求
很有帮助。
如果预检:
没匹配某条 Route
仍然可以:
处理全局 CORS
一百一十一、为什么浏览器先发 OPTIONS
复杂跨域请求时:
浏览器先问服务器:
“我能不能这样请求?”
这就是:
Preflight
一百一十二、CORS 常见错误:Gateway 和服务都加
Gateway:
加 Access-Control-Allow-Origin
下游服务:
也加
结果可能:
响应头重复
浏览器仍然报跨域。
一百一十三、建议
如果所有外部流量统一 Gateway:
优先在 Gateway 统一处理 CORS
内部服务:
通常不需要再对浏览器开放 CORS
一百一十四、allowCredentials 与 *
如果:
allowCredentials=true
不要简单使用:
allowedOrigins: "*"
应该:
明确允许的前端 Origin
一百一十五、为什么
凭证跨域:
安全要求更严格
Spring CORS 配置也会对此进行校验。
一百一十六、生产 Origin
不要:
localhost
而是:
真实前端域名
例如:
https://app.example.com
一百一十七、自动发现路由
Gateway 可以结合:
DiscoveryClient
自动为服务建立路由。
一百一十八、开启 Discovery Locator
Spring Cloud 2025.0.x:
spring:
cloud:
gateway:
server:
webflux:
discovery:
locator:
enabled: true
一百一十九、默认思想
服务:
user-service
可以形成基于:
/serviceId/**
的路由。
目标 URI:
lb://serviceId
一百二十、为什么自动路由很方便
10 个服务:
不用全部手写 Route
一百二十一、为什么课程项目仍推荐显式 Route
因为:
前端 API 路径
不一定等于服务名
还可能需要:
StripPrefix
权限
特定 Filter
版本管理
显式 Route:
更可控
一百二十二、所以自动发现适合什么
快速测试
内部简单环境
统一服务命名规范
一百二十三、生产路由更常见
显式配置关键 Route
一百二十四、路由可以写 Java
除了 YAML,
可以使用:
RouteLocatorBuilder
一百二十五、Java DSL 示例
@Bean
public RouteLocator customRouteLocator(
RouteLocatorBuilder builder
) {
return builder
.routes()
.route(
"user-route",
r -> r
.path("/api/users/**")
.filters(
f -> f.stripPrefix(1)
)
.uri("lb://user-service")
)
.build();
}
一百二十六、YAML 和 Java DSL 怎么选
普通固定路由:
YAML
最直观。
复杂动态逻辑:
Java DSL
可能更灵活。
一百二十七、不要把所有 Route 都硬编码 Java
配置型路由:
YAML / 配置中心
通常维护更方便。
一百二十八、动态路由是什么
不重启 Gateway:
增加/修改路由
就叫:
动态路由
一百二十九、为什么需要动态路由
微服务很多:
路由经常变化
如果每次:
改 application.yml
重启 Gateway
比较麻烦。
一百三十、常见实现
Nacos 配置中心
保存 Gateway 路由。
然后 Gateway:
监听配置变化
刷新 RouteDefinition
一百三十一、当前课要做到什么程度
先理解:
动态路由思想
后面若依 Cloud:
会看到真实实现
这里不要求:
手写复杂动态路由监听器
一百三十二、为什么不建议初学者直接复制网上动态路由代码
不同 Gateway 版本:
RouteDefinition API
配置前缀
刷新机制
可能变化。
先把:
静态路由
学扎实。
一百三十三、Gateway 超时
Gateway 自己:
也要有网络超时
因为它负责:
转发下游服务
一百三十四、Connect Timeout
Spring Cloud Gateway 支持:
HTTP Client connect timeout
一百三十五、Response Timeout
还需要考虑:
下游响应等待时间
一百三十六、为什么不能 Gateway 无限等
下游慢:
Gateway 连接资源会被长期占用
最终:
入口也被拖垮
一百三十七、超时层次
Client → Gateway timeout
Gateway → Service timeout
Service → Feign Service timeout
每一层:
都要有边界
一百三十八、超时不要互相矛盾
例如:
Gateway 2 秒
下游 Feign 10 秒
那么外部:
2 秒已经断
内部还可能:
继续处理很久
一百三十九、超时预算
企业会考虑:
End-to-End Timeout Budget
例如用户最多等:
5 秒
再把时间:
分配给各个调用层
一百四十、Gateway Retry Filter
Gateway 支持:
Retry
但一定记:
重试不是越多越好
一百四十一、为什么入口重试更危险
一个用户请求:
Gateway 自动重试 3 次
内部负载瞬间:
放大
如果下游已经过载:
重试风暴
一百四十二、写操作尤其危险
例如:
POST /orders
不能因为:
Gateway 重试
就重复创建订单。
一百四十三、所以 Retry 必须考虑
HTTP Method
幂等性
错误类型
最大次数
退避
一百四十四、Gateway RequestRateLimiter
Gateway 自带:
RequestRateLimiter
过滤器。
一百四十五、WebFlux 常见 Redis RateLimiter
需要:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>
spring-boot-starter-data-redis-reactive
</artifactId>
</dependency>
一百四十六、为什么是 redis-reactive
Gateway Server WebFlux:
反应式
所以:
使用 Reactive Redis
而不是在 Filter 中使用阻塞式 RedisTemplate。
一百四十七、RequestRateLimiter 默认拒绝状态
官方默认:
HTTP 429
也就是:
Too Many Requests
一百四十八、KeyResolver
限流必须回答:
“按谁限?”
这就是:
KeyResolver
一百四十九、例如按 IP
@Bean
public KeyResolver ipKeyResolver() {
return exchange -> {
InetSocketAddress address =
exchange
.getRequest()
.getRemoteAddress();
String host =
address == null
? "unknown"
: address
.getAddress()
.getHostAddress();
return Mono.just(host);
};
}
一百五十、例如按用户
可以根据:
认证后的 userId
作为 Key。
一百五十一、为什么比全局 QPS 更精细
总接口:
1000 QPS
但单个用户:
最多 10 QPS
可以防止:
一个用户占满全部容量
一百五十二、Redis RateLimiter Token Bucket
核心配置:
replenishRate
burstCapacity
requestedTokens
一百五十三、replenishRate
每秒补充多少 Token
一百五十四、burstCapacity
Token 桶最大容量
允许:
短时突发
一百五十五、requestedTokens
一个请求:
消耗多少 Token
默认:
1
一百五十六、示例
filters:
- name: RequestRateLimiter
args:
key-resolver: "#{@ipKeyResolver}"
redis-rate-limiter.replenishRate: 10
redis-rate-limiter.burstCapacity: 20
redis-rate-limiter.requestedTokens: 1
一百五十七、这是什么意思
稳定速率:
每秒 10 个
短时桶容量:
20
允许一定:
瞬间突发
一百五十八、Gateway 限流和 Sentinel 限流区别
Gateway RequestRateLimiter:
入口限流
Sentinel:
服务/资源治理
一百五十九、可以组合
Gateway
先挡明显大流量
↓
业务服务 Sentinel
再保护具体资源
一百六十、不要重复无脑限两套
关键是:
容量设计
不是:
组件越多越安全
一百六十一、Gateway + Sentinel
Sentinel 有:
Gateway Adapter
可以针对:
Route
API 分组
做流控。
一百六十二、课程现在为什么不深挖
上一课已经详细学:
Sentinel 核心
这一课重点:
Gateway 本身
只要理解:
Gateway 入口也能接 Sentinel
即可。
一百六十三、下一阶段项目会看到
Gateway
+
Sentinel
+
Nacos
组合治理。
一百六十四、GlobalFilter 做日志要记录什么
推荐:
TraceId
Method
Path
RouteId
Status
Cost
一百六十五、不要默认记录什么
Password
Authorization 完整 Token
银行卡
身份证敏感信息
一百六十六、TraceId
如果客户端没传:
Gateway 生成
然后:
向下游传递
一百六十七、TraceId GlobalFilter 思想
Request
↓
读取 X-Trace-Id
↓
没有则生成 UUID
↓
写入 Request Header
↓
写入日志 MDC
↓
下游继续传播
一百六十八、为什么 TraceId 从 Gateway 生成很合理
因为:
Gateway 是外部请求统一入口
适合作为:
链路起点
一百六十九、但消息队列链路怎么办
后面 MQ 阶段会学:
Trace Context 继续传播
一百七十、Gateway 不应该成为单点故障
如果整个系统:
只有一个 Gateway 实例
Gateway 挂:
所有外部请求都进不来
一百七十一、生产应该
多个 Gateway 实例
再由:
Nginx
云负载均衡
Kubernetes Service
在前面分流。
一百七十二、典型生产结构
Internet
↓
Load Balancer / Nginx
├─ Gateway 1
├─ Gateway 2
└─ Gateway 3
↓
Microservices
一百七十三、Gateway 自己要不要注册 Nacos
如果只是:
最外层由 Nginx 固定代理 Gateway
Gateway 自己是否注册:
根据架构
课程为了统一微服务管理:
可以注册
一百七十四、Gateway 本身可以无状态
推荐:
不要把用户 Session 放 Gateway 单机内存
一百七十五、为什么
多个 Gateway 实例:
请求会随机进入
如果状态只在 Gateway 1:
Gateway 2 不知道
一百七十六、认证状态
可以使用:
JWT
Redis
等共享方案。
一百七十七、Gateway 和 Redis
Redis 可以用于:
Token Session
黑名单
限流
验证码状态
但 Gateway Filter:
尽量使用非阻塞访问方式
一百七十八、Gateway 里调用 Feign 合适吗
通常:
不建议把 Gateway 当业务聚合服务
一百七十九、为什么
Feign 传统调用可能:
引入阻塞式调用模型
Gateway WebFlux:
强调非阻塞
而且:
职责会变重
一百八十、如果需要 API 聚合
可以考虑:
专门 BFF
Aggregator Service
而不是把 Gateway:
写成业务 Service
一百八十一、什么是 BFF
Backend For Frontend:
为特定前端提供聚合接口
例如:
App BFF
Web BFF
一百八十二、Gateway 和 BFF 区别
Gateway:
统一入口和横切治理
BFF:
页面/客户端业务聚合
一百八十三、Gateway 里的数据库访问
不是说:
绝对不能
而是:
应该非常克制
例如每个请求同步查:
MySQL
会影响 Gateway:
高吞吐入口能力
一百八十四、权限数据怎么办
常见:
Token 内携带必要 Claims
或者:
Redis 非阻塞读取轻量会话
复杂权限:
下沉业务服务
一百八十五、白名单匹配不要只 startsWith
例如:
path.startsWith("/api/public")
可能错误放过:
/api/publicFakeDanger
一百八十六、推荐
使用:
PathPattern
AntPathMatcher
或框架对应的安全 Matcher。
一百八十七、路径安全还要防绕过
例如:
重复斜杠
URL 编码
Path Traversal
生产鉴权:
优先使用成熟 Security 机制
一百八十八、课程手写 GlobalFilter 的目的
是让你理解:
认证发生在哪里
不是鼓励生产:
自己重新造整套安全框架
一百八十九、若依 Cloud 后面会看到
成熟脚手架已经:
封装 Gateway 鉴权
Remote Service
Security Context
白名单
到时重点:
理解而不是推倒重写
一百九十、Gateway Actuator
加入:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>
spring-boot-starter-actuator
</artifactId>
</dependency>
一百九十一、为什么有用
可以查看:
实际 Route
实际 Filter
Gateway Metrics
一百九十二、查看 Routes
Gateway Actuator 提供:
/actuator/gateway/routes
可以看到:
route_id
predicate
filters
uri
一百九十三、为什么这是排错神器
你以为配置:
已经加载
但实际上:
路由根本没注册
看 Actuator:
马上知道
一百九十四、不要生产直接暴露所有 Actuator
安全原则:
只开放必要 endpoint
内部网络
认证保护
一百九十五、Gateway Metrics
开启 Actuator 后,
Gateway 可以产生:
spring.cloud.gateway.requests
相关指标。
一百九十六、指标可关注
RouteId
Status
Outcome
请求时间
一百九十七、为什么 Gateway Metrics 很重要
Gateway 是:
所有请求入口
它天然适合看到:
哪个服务请求最多
哪个 Route 错误最多
一百九十八、Gateway 访问日志
Reactor Netty 也支持:
Access Log
可以用于:
入口请求日志
但生产:
日志量很大
要合理采集。
一百九十九、Route ID 命名
不要:
route1
route2
route3
推荐:
user-service-route
order-service-route
travel-service-route
二百、为什么 Route ID 很重要
日志和监控:
都会看到 RouteId
名字清晰:
排错更快
二百零一、URI 的三种常见形式
第一:
http://host:port
固定地址。
第二:
https://host
第三方服务。
第三:
lb://service-name
微服务发现。
二百零二、内部服务推荐
lb://service-name
二百零三、外部 API
可以:
https://xxx
但是:
要配置超时
安全
熔断
二百零四、Gateway 与服务上下文路径
如果 Provider:
server:
servlet:
context-path: ...
注意:
WebFlux/MVC 服务路径差异
Gateway 路径必须:
和下游真实 URI 对齐
二百零五、为什么建议业务服务路径清晰
例如:
/user/**
和:
/api/user/**
各层一定约定清楚。
二百零六、推荐外部统一前缀
例如:
/api
外部:
/api/users/**
内部:
/users/**
Gateway:
StripPrefix=1
二百零七、为什么这样好
前端:
所有后端 API 都在 /api
Nginx:
也容易代理
二百零八、Web 前端代理
开发阶段 Vue Vite:
也可以 proxy /api 到 Gateway
二百零九、生产
Browser
↓
Nginx
/api/**
↓
Gateway
↓
Microservices
二百一十、Gateway 路由与前端 baseURL
前端 Axios:
baseURL=/api
Gateway:
负责之后所有服务路由
二百一十一、前端不应该知道 service-name
不要让前端请求:
/user-service/users/1
除非这是:
明确设计的公开 API
二百一十二、服务名属于内部架构细节
外部接口:
应该稳定
内部:
可以重构服务名
二百一十三、这叫解耦
外部 API
≠
内部微服务拓扑
二百一十四、Gateway 的路由就是一个解耦层
后面 user-service 改名:
account-service
前端仍可以:
/api/users/**
只要 Gateway Route 修改。
二百一十五、Gateway 返回错误格式
默认错误可能是:
Spring WebFlux 默认错误 JSON
企业项目通常希望:
统一响应格式
二百一十六、哪些错误可以统一
例如:
401 未登录
403 无权限
429 限流
503 服务不可用
二百一十七、但是 Gateway 异常处理是反应式
不能照搬:
@RestControllerAdvice
所有 MVC 异常处理方式。
二百一十八、常见方案
ErrorWebExceptionHandler
WebExceptionHandler
GlobalFilter
结合项目架构处理。
二百一十九、课程先不手写完整统一异常框架
因为下一步:
若依 Cloud
会有现成实现可分析。
二百二十、但你要知道为什么普通 @ControllerAdvice 不一定管得到
因为 Gateway:
路由链路不是普通 MVC Controller 调用链
二百二十一、Gateway WebFlux 常见错误 1
项目同时加入:
spring-boot-starter-web
导致:
Web 应用类型冲突
二百二十二、解决
Gateway WebFlux:
不要随便引入 MVC Web Starter
检查:
mvn dependency:tree
二百二十三、错误 2:旧 Starter 名称
照旧教程:
spring-cloud-starter-gateway
在 2025.x 仍可能遇到:
迁移/弃用提示
新项目:
spring-cloud-starter-gateway-server-webflux
二百二十四、错误 3:旧配置前缀
旧:
spring.cloud.gateway.routes
课程 2025.0.x:
spring.cloud.gateway.server.webflux.routes
二百二十五、为什么旧教程有时还能跑
Spring Cloud 2025.0 引入:
属性迁移机制
有些旧属性:
可能能通过迁移工具过渡
但:
不要把兼容层当新标准
二百二十六、错误 4:lb:// 找不到服务
检查:
Nacos Discovery
LoadBalancer
service name
Namespace
实例健康
二百二十七、错误 5:Gateway 404
检查:
Route 是否加载
Path Predicate
StripPrefix
Provider Controller path
二百二十八、错误 6:Gateway 503
通常:
找不到 lb 服务实例
二百二十九、错误 7:CORS 还是报错
检查:
OPTIONS
Gateway globalcors
allowedOrigins
allowCredentials
下游是否重复加 CORS Header
二百三十、错误 8:GlobalFilter 不执行
检查:
@Component
是否实现 GlobalFilter
是否请求真正经过 Gateway Route
二百三十一、错误 9:Filter 顺序不对
检查:
Ordered#getOrder
二百三十二、错误 10:JWT Header 被伪造
检查:
是否先删除客户端 X-User-Id
再由 Gateway 重新设置
二百三十三、错误 11:Gateway CPU 不高但请求卡死
检查:
有没有阻塞代码
Thread.sleep
阻塞 JDBC
阻塞 Redis
同步远程调用
二百三十四、错误 12:Actuator 看不到 Gateway Routes
检查:
Actuator 依赖
endpoint 是否暴露
Gateway endpoint 权限
二百三十五、错误 13:RequestRateLimiter 不生效
检查:
Reactive Redis
KeyResolver Bean
Route Filter 配置
Redis 连接
Key 是否为空
二百三十六、KeyResolver 返回空 Key
Gateway RequestRateLimiter:
可能拒绝请求
所以:
Key 解析要有明确策略
二百三十七、错误 14:真实客户端 IP 永远是 Nginx
因为 Gateway 前面:
还有代理
getRemoteAddress:
看到的可能是 Nginx IP
二百三十八、这时会涉及
Forwarded
X-Forwarded-For
Trusted Proxies
二百三十九、2025.0.x 的一个重要安全变化
Spring Cloud 2025.0 对:
Forwarded / X-Forwarded
信任策略做了更严格调整。
不要:
无条件相信客户端自己传的 X-Forwarded-For
二百四十、为什么
攻击者可以伪造:
X-Forwarded-For
绕过:
按 IP 限流
IP 白名单
二百四十一、生产要配置可信代理
Gateway 应该知道:
哪些代理地址值得信任
再接受:
Forwarded Header
二百四十二、错误 15:Gateway 日志打印完整 Token
这是:
安全问题
日志:
不要记录完整 Authorization
二百四十三、错误 16:Gateway 里做权限 SQL
表现:
每个请求都同步查数据库
Gateway:
吞吐下降
二百四十四、错误 17:所有业务都塞 GlobalFilter
GlobalFilter 最终:
上千行
说明:
Gateway 职责开始失控
二百四十五、正确拆分
Trace Filter
Auth Filter
Log Filter
职责:
单一
复杂业务:
下沉业务服务
二百四十六、错误 18:Gateway Retry 重试 POST
结果:
重复业务
必须检查:
幂等
二百四十七、错误 19:Gateway 与 Sentinel 阈值冲突
外层:
1000
内层:
10
导致:
大量请求已经进入内部才被挡
需要统一:
容量规划
二百四十八、错误 20:只有一个 Gateway
生产:
形成入口单点
二百四十九、完整微服务架构
Internet
│
▼
Nginx / LB
│
┌───────────┴───────────┐
▼ ▼
Gateway-1 Gateway-2
│ │
└───────────┬───────────┘
▼
Nacos
│
┌──────────────┼──────────────┐
▼ ▼ ▼
user-service order-service travel-service
│ │ │
└────── Feign / MQ / DB ──────┘
二百五十、Gateway 在整个体系中的位置
Nacos
→ 服务发现
Feign
→ 服务之间调用
Sentinel
→ 服务稳定性保护
Gateway
→ 外部统一入口
二百五十一、这四个组件现在就串起来了
用户请求:
Vue
↓
Gateway
↓
lb://order-service
↓
Nacos 找实例
↓
Order Service
↓
Feign
↓
User Service
↓
Sentinel 保护调用
二百五十二、IDEA 项目结构建议
spring-cloud-demo
├─ gateway
├─ user-api
├─ user-service
├─ order-service
└─ common
二百五十三、gateway 包结构
gateway
└─ src/main/java
└─ com.example.gateway
├─ GatewayApplication.java
├─ config
├─ filter
├─ handler
└─ properties
二百五十四、不要给 gateway 建 mapper/service/controller 一大套
除非:
确实有 Gateway 自己的管理需求
否则它不是:
普通 CRUD 服务
二百五十五、学习实验 1:固定 URI 路由
先:
uri=http://localhost:8081
验证:
Gateway 最基础路由
二百五十六、实验 2:改成 lb://
lb://user-service
验证:
Nacos + LoadBalancer
二百五十七、实验 3:多实例
user-service:
8081 + 8083
通过 Gateway 连续访问:
观察实例切换
二百五十八、实验 4:Path Predicate
只匹配:
/api/users/**
二百五十九、实验 5:Method Predicate
只允许:
GET
看 POST:
不匹配路由
二百六十、实验 6:StripPrefix
客户端:
/api/users/1
Provider:
/users/1
设置:
StripPrefix=1
二百六十一、实验 7:AddRequestHeader
Gateway 加:
X-Gateway=demo
Provider 打印 Header。
二百六十二、实验 8:GlobalFilter
打印:
path
method
耗时
二百六十三、实验 9:Filter Order
创建:
Filter A
Filter B
分别:
-100
0
观察:
pre/post 顺序
二百六十四、实验 10:CORS
Vue:
localhost:5173
Gateway:
localhost:8080
验证:
OPTIONS + 真正请求
二百六十五、实验 11:JWT 白名单
白名单:
/login
普通:
/orders
没有 Token:
401
二百六十六、实验 12:伪造 X-User-Id
客户端手工:
X-User-Id: 1
Gateway:
必须删除
再根据 Token:
重建
二百六十七、实验 13:服务下线
关闭 user-service。
Gateway:
访问 lb://user-service
观察:
503
二百六十八、实验 14:Actuator Route
查看:
/actuator/gateway/routes
确认:
真实 Route
二百六十九、实验 15:RequestRateLimiter
按:
IP
限流。
快速请求:
观察 429
二百七十、Gateway 高频面试题 1
问题:
什么是 API Gateway?
答案:
API Gateway 是微服务系统的统一入口。
客户端不需要直接感知内部所有服务地址,
请求先进入 Gateway,
再根据路由规则转发到具体服务。
Gateway 还可以统一处理认证、跨域、日志、
限流和请求头等横切逻辑。
二百七十一、面试题 2:Route 包含什么
答:
Route 是 Gateway 的基本路由单元。
通常包括:
Route ID、
目标 URI、
Predicate 集合、
Filter 集合。
请求满足 Predicate 后,
经过 Filter 处理,
最终转发到 URI。
二百七十二、面试题 3:Predicate 和 Filter 区别
答:
Predicate 决定一个请求是否匹配当前 Route。
Filter 则在 Route 已匹配之后,
对请求或响应进行修改和处理。
可以记成:
Predicate 决定“走不走这条路”,
Filter 决定“路上做什么”。
二百七十三、面试题 4:lb:// 是什么
答:
lb:// 表示目标不是固定 IP,
而是一个逻辑服务名。
Gateway 会结合 Spring Cloud LoadBalancer
和服务发现组件获取实例,
再选择真实 Host 和 Port 转发请求。
二百七十四、面试题 5:Gateway 与 Nacos 如何配合
答:
Nacos 提供服务注册和发现。
Gateway Route 使用 lb://service-name 时,
可以从服务发现体系获得当前可用实例,
再由 LoadBalancer 选择一个实例进行转发。
因此 Gateway 不需要写死内部服务 IP。
二百七十五、面试题 6:Gateway 和 Nginx 区别
答:
Nginx 更偏网络入口、TLS、静态资源和高性能反向代理。
Spring Cloud Gateway 更偏 Spring Cloud 应用层路由,
能够直接整合服务发现、Java 过滤器、认证上下文和微服务治理。
实际项目中两者经常同时存在。
二百七十六、面试题 7:Gateway 为什么用 WebFlux
答:
Gateway Server WebFlux 建立在 Spring WebFlux、
Project Reactor 和 Reactor Netty 上,
适合处理大量网络代理连接。
因此 Filter 使用 Mono 和 ServerWebExchange,
不能简单照搬传统 Servlet 阻塞式编程方式。
二百七十七、面试题 8:为什么 Gateway 不能阻塞
答:
WebFlux Gateway 依赖少量事件循环线程处理大量网络请求。
如果 Filter 中执行 Thread.sleep、
阻塞式 JDBC 或长时间同步操作,
会占用事件循环线程,
导致大量其他请求也无法及时处理。
因此 Gateway 应保持轻量、非阻塞。
二百七十八、面试题 9:GatewayFilter 和 GlobalFilter 区别
答:
GatewayFilter 通常绑定到具体 Route,
只处理该路由请求。
GlobalFilter 会参与所有匹配 Gateway 路由的请求链,
适合统一日志、TraceId 和认证等横切能力。
二百七十九、面试题 10:Filter 顺序怎么判断
答:
GlobalFilter 和 GatewayFilter 会组成过滤器链,
并按照 Ordered 等顺序规则排序。
数值越小通常优先级越高。
高优先级 Filter 在 pre 阶段更早执行,
在 post 阶段更晚执行。
二百八十、面试题 11:StripPrefix 做什么
答:
StripPrefix 会在请求转发下游之前,
删除指定数量的 URL Path Segment。
例如 /api/users/1 使用 StripPrefix=1 后,
下游收到 /users/1。
二百八十一、面试题 12:Gateway 怎么处理跨域
答:
Gateway 可以配置全局 CORS 或 Route 级 CORS。
当所有浏览器请求统一经过 Gateway 时,
通常推荐在 Gateway 集中处理跨域,
避免每个微服务分别配置并产生重复 CORS Header。
二百八十二、面试题 13:为什么 Gateway 可以做统一认证
答:
所有外部请求都经过 Gateway,
所以它适合在入口检查 Token、
识别白名单并解析基础用户身份。
但具体业务权限和数据权限
仍然应该由业务服务进行校验,
不能把 Gateway 作为唯一授权边界。
二百八十三、面试题 14:为什么不能信任客户端 X-User-Id
答:
客户端可以自行伪造 HTTP Header。
如果 Gateway 直接相信客户端提交的 X-User-Id,
攻击者可能冒充其他用户。
正确方式是删除外部传入的内部身份 Header,
根据经过验证的 Token 重新生成可信上下文。
二百八十四、面试题 15:为什么 Gateway 不建议大量查数据库
答:
Gateway 是高并发统一入口,
WebFlux 又强调非阻塞网络处理。
如果每次请求都执行阻塞式数据库查询,
容易拖慢事件循环和整个入口吞吐。
复杂业务权限应尽量下沉业务服务,
Gateway 只保留轻量横切逻辑。
二百八十五、面试题 16:什么是 RequestRateLimiter
答:
RequestRateLimiter 是 Gateway 的请求限流过滤器。
它根据 KeyResolver 计算限流 Key,
再通过 RateLimiter 判断请求是否允许通过。
WebFlux 中常用 RedisRateLimiter,
默认被限流的请求返回 HTTP 429。
二百八十六、面试题 17:Gateway 限流和 Sentinel 区别
答:
Gateway 限流更适合在统一外部入口尽早挡住流量。
Sentinel 更擅长保护内部具体服务和资源,
并提供熔断、慢调用和热点参数等治理能力。
两者可以分层组合,但阈值应统一进行容量设计。
二百八十七、面试题 18:Gateway 为什么会成为单点
答:
如果整个系统只有一个 Gateway 实例,
它一旦宕机,所有外部请求都无法进入微服务系统。
因此生产环境通常部署多个 Gateway 实例,
再由 Nginx、云负载均衡或 Kubernetes Service
在前面进行流量分配。
二百八十八、面试题 19:2025.0.x Gateway 有什么重要变化
答:
Spring Cloud 2025.0 对 Gateway 模块名称和配置前缀进行了迁移。
Server WebFlux 推荐 Starter:
spring-cloud-starter-gateway-server-webflux。
配置前缀也从旧式 spring.cloud.gateway.*
迁移到 spring.cloud.gateway.server.webflux.*。
新项目应直接采用新命名。
二百八十九、面试题 20:Gateway 最大价值是什么
答:
Gateway 最大价值不是简单转发 URL,
而是为微服务提供稳定统一的外部 API 边界。
客户端与内部服务拓扑解耦,
路由、认证、跨域、限流、日志等横切能力
可以集中治理,
内部服务也可以独立扩缩容和演进。
二百九十、Cursor 提示词:创建 Gateway
当前父工程:
JDK17
Spring Boot 3.5.x
Spring Cloud 2025.0.x
Spring Cloud Alibaba 2025.0.x
已有:
user-service
order-service
Nacos
请创建 gateway 模块。
要求:
1. 使用 spring-cloud-starter-gateway-server-webflux
2. 不使用旧 spring-cloud-starter-gateway 作为新项目主方案
3. 不引入 spring-boot-starter-web
4. Gateway 注册 Nacos
5. 显式引入 Spring Cloud LoadBalancer
6. gateway 端口 8080
7. 不加入业务 Mapper/数据库代码
二百九十一、Cursor 提示词:Route
请给 Gateway 添加两条显式 Route:
/api/users/**
→ lb://user-service
/api/orders/**
→ lb://order-service
要求:
1. 使用 Spring Cloud 2025.0.x 新配置前缀
spring.cloud.gateway.server.webflux.routes
2. 每条 Route 有清晰 id
3. 使用 Path Predicate
4. 使用 StripPrefix=1
5. 不写死 localhost:8081/8082
6. 给出最终请求路径变化示意
二百九十二、Cursor 提示词:旧配置迁移
请审查 gateway application.yml。
当前技术栈是 Spring Cloud 2025.0.x。
检查是否仍使用:
spring.cloud.gateway.routes
spring.cloud.gateway.globalcors
spring-cloud-starter-gateway-server
如果有,请说明对应的新:
spring.cloud.gateway.server.webflux.*
spring-cloud-starter-gateway-server-webflux
先输出迁移清单,不要无脑修改其他配置。
二百九十三、Cursor 提示词:Path 404 排查
Gateway 返回 404。
请按以下链路分析:
1. 客户端原始 Path
2. Route Path Predicate
3. StripPrefix / RewritePath 处理后 Path
4. lb:// service-name
5. Provider 实际 Controller @RequestMapping
6. Nacos 是否存在实例
请把每一步的“实际值”列出来,
不要只说检查配置。
二百九十四、Cursor 提示词:GlobalFilter
请实现一个轻量 Gateway GlobalFilter。
要求:
1. 使用 WebFlux GlobalFilter
2. 使用 ServerWebExchange
3. 记录 method/path/status/cost
4. 实现 Ordered
5. 不使用 Thread.sleep
6. 不使用阻塞 JDBC
7. 不打印完整 Authorization Token
8. 说明 pre/post 执行顺序
二百九十五、Cursor 提示词:JWT 鉴权
请设计 Gateway JWT 入口鉴权。
要求:
1. 白名单配置化
2. 非白名单检查 Authorization
3. 校验 Token
4. 从 Token 获取 userId
5. 删除客户端原始 X-User-Id
6. 重新写入可信 X-User-Id
7. Token 无效返回 401
8. Gateway 只做基础认证
9. 业务 RBAC/DataScope 仍由业务服务处理
10. 使用 WebFlux API,不使用 HttpServletRequest
二百九十六、Cursor 提示词:CORS
请按 Spring Cloud 2025.0.x Gateway Server WebFlux
配置全局 CORS。
要求:
1. 使用 spring.cloud.gateway.server.webflux.globalcors
2. 支持 localhost:5173
3. GET/POST/PUT/DELETE/OPTIONS
4. 处理预检请求
5. allowCredentials=true 时不要 allowedOrigins="*"
6. 检查下游服务是否重复添加 CORS Header
二百九十七、Cursor 提示词:限流
请给 Gateway 的 order Route 加 RequestRateLimiter。
要求:
1. 使用 Reactive Redis
2. 创建按 IP KeyResolver
3. replenishRate=10
4. burstCapacity=20
5. requestedTokens=1
6. 说明 Token Bucket 原理
7. 被限流返回 429
8. 不使用阻塞 RedisTemplate
二百九十八、Cursor 提示词:安全审查
请审查 Gateway 安全风险。
重点检查:
1. 是否信任客户端 X-User-Id
2. 是否记录完整 Token
3. 白名单是否过宽
4. Actuator 是否公网暴露
5. CORS 是否 allowedOrigins=* + credentials
6. 是否信任任意 X-Forwarded-For
7. 是否有未限制的大文件请求
8. 是否有 Gateway Retry 重试非幂等 POST
9. 下游服务是否仍能直接公网访问
10. 是否把完整业务授权只放 Gateway
二百九十九、Cursor 提示词:WebFlux 阻塞审查
请审查 gateway 模块是否存在阻塞代码。
查找:
1. Thread.sleep
2. JDBC / MyBatis
3. RestTemplate
4. 阻塞 RedisTemplate
5. Future.get
6. 同步文件 IO
7. 长时间 CPU 操作
8. 在 GlobalFilter 中复杂数据库权限查询
说明每处为什么可能阻塞 Reactor Netty。
不要直接全部改,先分风险等级。
三百、Cursor 提示词:Gateway + Nacos
请检查 Gateway 的 lb:// 路由为什么返回 503。
按顺序检查:
1. gateway 是否注册/连接 Nacos
2. Provider 是否注册
3. service-name 是否完全一致
4. Namespace 是否一致
5. Provider 是否健康
6. spring-cloud-starter-loadbalancer 是否存在
7. Route URI 是否 lb://xxx
8. mvn dependency:tree 是否存在版本冲突
三百零一、本章知识树
Spring Cloud Gateway
│
├─ Core
│ ├─ Route
│ ├─ Predicate
│ ├─ GatewayFilter
│ └─ GlobalFilter
│
├─ Routing
│ ├─ Path
│ ├─ Method
│ ├─ Header
│ ├─ Query
│ ├─ Host
│ ├─ RemoteAddr
│ └─ Time
│
├─ Service Discovery
│ ├─ Nacos
│ ├─ lb://
│ ├─ LoadBalancer
│ └─ Discovery Locator
│
├─ Filter
│ ├─ StripPrefix
│ ├─ RewritePath
│ ├─ PrefixPath
│ ├─ AddRequestHeader
│ ├─ RemoveRequestHeader
│ ├─ RequestSize
│ └─ Retry
│
├─ WebFlux
│ ├─ Reactor Netty
│ ├─ Mono
│ ├─ ServerWebExchange
│ ├─ ServerHttpRequest
│ └─ Non-blocking
│
├─ Security
│ ├─ JWT
│ ├─ White List
│ ├─ Internal Headers
│ ├─ 401
│ ├─ CORS
│ └─ Trusted Proxy
│
├─ Rate Limit
│ ├─ RequestRateLimiter
│ ├─ KeyResolver
│ ├─ Reactive Redis
│ └─ Token Bucket
│
├─ Observability
│ ├─ TraceId
│ ├─ Logging
│ ├─ Metrics
│ └─ Actuator Routes
│
└─ High Availability
├─ Multiple Gateway Instances
├─ Nginx/LB
├─ Timeout
└─ Sentinel
三百零二、四大组件总复习
Nacos
→ 服务在哪里?
Feign
→ 服务之间怎么方便调用?
Sentinel
→ 服务怎么防止被流量和下游故障拖垮?
Gateway
→ 外部请求统一从哪里进入?
三百零三、完整调用流程
Vue
↓
Nginx
↓
Gateway
│
├─ CORS
├─ TraceId
├─ JWT
├─ Route
├─ Rate Limit
│
↓ lb://order-service
Nacos + LoadBalancer
↓
Order Service
↓
Feign
↓
User Service
↓
Sentinel
三百零四、本章最重要的 20 条原则
1. Gateway 是统一入口,不是超级业务服务
2. 2025.0.x 新项目使用 gateway-server-webflux Starter
3. 2025.0.x 配置优先使用 spring.cloud.gateway.server.webflux.*
4. Gateway Server WebFlux 不要无脑混入 spring-boot-starter-web
5. Route = id + uri + predicates + filters
6. Predicate 决定请求是否匹配
7. Filter 决定匹配后如何处理
8. 内部微服务 URI 优先 lb://service-name
9. Nacos 负责发现实例,LoadBalancer 负责选择实例
10. StripPrefix 最容易导致路径 404,必须画路径变化
11. GlobalFilter 适合统一横切逻辑
12. WebFlux GlobalFilter 中不要执行阻塞操作
13. Gateway 可做基础认证,但不能替代业务授权
14. 永远不要信任客户端伪造的内部身份 Header
15. 所有浏览器流量统一 Gateway 时优先统一配置 CORS
16. Gateway Retry 必须考虑幂等
17. Gateway 限流越早拒绝,内部资源浪费越少
18. Gateway 也需要超时、监控和高可用
19. Actuator Routes 是 Gateway 排错的重要工具
20. 外部 API 与内部微服务拓扑应该解耦
三百零五、本章最终验收
学完以后,你应该能独立回答和完成:
1. Gateway 为什么存在
2. Gateway 和 Nginx 区别
3. Gateway Server WebFlux 是什么
4. 为什么不能混用 Servlet 阻塞思维
5. 2025.0.x Starter 新名称
6. 2025.0.x Gateway 新配置前缀
7. 创建 gateway Maven 模块
8. Gateway 注册 Nacos
9. Route 四大组成
10. Path Predicate
11. Method Predicate
12. Header Predicate
13. Query Predicate
14. lb://service-name
15. Nacos + LoadBalancer 路由
16. StripPrefix
17. RewritePath
18. PrefixPath
19. AddRequestHeader
20. RemoveRequestHeader
21. GatewayFilter
22. GlobalFilter
23. Ordered
24. pre/post 顺序
25. ServerWebExchange
26. Mono<Void>
27. WebFlux 非阻塞要求
28. CORS
29. OPTIONS 预检
30. JWT 基础入口鉴权
31. 白名单
32. 防止 X-User-Id 伪造
33. RequestRateLimiter
34. KeyResolver
35. Reactive Redis
36. Token Bucket
37. Gateway + Sentinel 分层治理
38. Gateway Timeout
39. Gateway Retry 幂等风险
40. Actuator 查看路由
41. Gateway 多实例高可用
42. Trusted Proxy 与 X-Forwarded-For 风险
43. 动态路由基本思想
44. Discovery Locator
45. Gateway 为什么不能做大量数据库业务
三百零六、第四阶段前四课已经形成完整基础
到这里已经完成:
第 1 课
微服务体系架构
第 2 课
Nacos + Feign
第 3 课
Sentinel
第 4 课
Gateway
你已经可以把最基础的 Spring Cloud Alibaba 微服务链路串起来:
Gateway
↓
Nacos
↓
LoadBalancer
↓
Service
↓
Feign
↓
Service
↓
Sentinel
三百零七、下一课
按照课程表,下一篇进入:
《若依 Cloud 框架部署与代码修改器使用》
下一课最大的变化是:
不再从零手写微服务骨架
而是开始阅读:
一个已经搭好的企业级微服务脚手架
重点会讲:
若依 Cloud 是什么
为什么它不是前面的 RuoYi-Vue 单体版
项目模块结构
ruoyi-gateway
ruoyi-auth
ruoyi-system
ruoyi-modules
ruoyi-api
ruoyi-common
Nacos 配置
Gateway 路由
Feign Remote Service
Sentinel
Redis
登录认证链
权限传递
服务启动顺序
数据库初始化
Nacos 配置导入
前后端启动
代码修改器/生成器如何使用
如何增加自己的业务微服务
哪些框架代码不要乱改
也就是说:
前四课学的是“零件”
下一课开始:
看一辆已经组装好的车
这会非常重要,因为你会真正明白:
Nacos、Feign、Sentinel、Gateway
在一个完整脚手架项目里
到底是怎么组织起来的