Spring Cloud Gateway常见问题总结
本文重构完善自6000 字 | 16 图 | 深入理解 Spring Cloud Gateway 的原理 - 悟空聊架构这篇文章。
什么是 Spring Cloud Gateway?
📝 通俗解释
以前大家都用 Netflix Zuul(第一代网关),但它老了,不维护了,性能也一般(阻塞IO)。
Spring 官方看不下去了,自己造了个轮子叫 Spring Cloud Gateway。
- 基于 Spring WebFlux:底层是 Netty,非阻塞 IO,性能比 Zuul 强很多。
- 亲儿子:Spring Cloud 生态里的东西,兼容性最好。
Spring Cloud Gateway 属于 Spring Cloud 生态系统中的网关,其诞生的目标是为了替代老牌网关 Zuul。准确点来说,应该是 Zuul 1.x。Spring Cloud Gateway 起步要比 Zuul 2.x 更早。
为了提升网关的性能,Spring Cloud Gateway 基于 Spring WebFlux 。Spring WebFlux 使用 Reactor 库来实现响应式编程模型,底层基于 Netty 实现同步非阻塞的 I/O。

Spring Cloud Gateway 不仅提供统一的路由方式,并且基于 Filter 链的方式提供了网关基本的功能,例如:安全,监控/指标,限流。
Spring Cloud Gateway 和 Zuul 2.x 的差别不大,也是通过过滤器来处理请求。不过,目前更加推荐使用 Spring Cloud Gateway 而非 Zuul,Spring Cloud 生态对其支持更加友好。
- GitHub 地址: https://github.com/spring-cloud/spring-cloud-gateway
- 官网: https://spring.io/projects/spring-cloud-gateway
Spring Cloud Gateway 的工作流程?
📝 通俗解释
就像**“安检通道”**。
- 路由(Route):你拿着票(请求),安检员看一眼,“哦,去北京的”,把你指到 3 号登机口(对应后端服务)。
- 断言(Predicate):安检员核对信息,“是今天的票吗?是本人吗?”(判断条件)。
- 过滤器(Filter):
- Pre(进去前):搜身,没带违禁品(鉴权、限流)。
- Post(出来后):给你盖个章,记录一下(日志、统计耗时)。
Spring Cloud Gateway 的工作流程如下图所示:

这是 Spring 官方博客中的一张图,原文地址:https://spring.io/blog/2022/08/26/creating-a-custom-spring-cloud-gateway-filter。
具体的流程分析:
- 路由判断:客户端的请求到达网关后,先经过 Gateway Handler Mapping 处理,这里面会做断言(Predicate)判断,看下符合哪个路由规则,这个路由映射后端的某个服务。
- 请求过滤:然后请求到达 Gateway Web Handler,这里面有很多过滤器,组成过滤器链(Filter Chain),这些过滤器可以对请求进行拦截和修改,比如添加请求头、参数校验等等,有点像净化污水。然后将请求转发到实际的后端服务。这些过滤器逻辑上可以称作 Pre-Filters,Pre 可以理解为“在...之前”。
- 服务处理:后端服务会对请求进行处理。
- 响应过滤:后端处理完结果后,返回给 Gateway 的过滤器再次做处理,逻辑上可以称作 Post-Filters,Post 可以理解为“在...之后”。
- 响应返回:响应经过过滤处理后,返回给客户端。
总结:客户端的请求先通过匹配规则找到合适的路由,就能映射到具体的服务。然后请求经过过滤器处理后转发给具体的服务,服务处理后,再次经过过滤器处理,最后返回给客户端。
Spring Cloud Gateway 的断言是什么?
📝 通俗解释
断言(Predicate)就是**“门槛”或者“条件”**。
就像代码里的if (xxx)。
只有满足了这个条件(比如 URL 里包含/api,或者请求头里有token),网关才会理你,把你路由到对应的服务去。
不满足?那就直接拒之门外,或者去匹配下一个路由。
断言(Predicate)这个词听起来极其深奥,它是一种编程术语,我们生活中根本就不会用它。说白了它就是对一个表达式进行 if 判断,结果为真或假,如果为真则做这件事,否则做那件事。
在 Gateway 中,如果客户端发送的请求满足了断言的条件,则映射到指定的路由器,就能转发到指定的服务上进行处理。
断言配置的示例如下,配置了两个路由规则,有一个 predicates 断言配置,当请求 url 中包含 api/thirdparty,就匹配到了第一个路由 route_thirdparty。

常见的路由断言规则如下图所示:

Spring Cloud Gateway 的路由和断言是什么关系?
📝 通俗解释
一对多的关系。
一个路由(Route)可以有好几个断言(Predicate)。
就像**“相亲标准”**:
- 身高要 180+(断言 1)。
- 收入要 20k+(断言 2)。
- 要有房(断言 3)。
这三个条件同时满足,这个路由(相亲对象)才算匹配成功。
Route 路由和 Predicate 断言的对应关系如下::

- 一对多:一个路由规则可以包含多个断言。如上图中路由 Route1 配置了三个断言 Predicate。
- 同时满足:如果一个路由规则中有多个断言,则需要同时满足才能匹配。如上图中路由 Route2 配置了两个断言,客户端发送的请求必须同时满足这两个断言,才能匹配路由 Route2。
- 第一个匹配成功:如果一个请求可以匹配多个路由,则映射第一个匹配成功的路由。如上图所示,客户端发送的请求满足 Route3 和 Route4 的断言,但是 Route3 的配置在配置文件中靠前,所以只会匹配 Route3。
Spring Cloud Gateway 如何实现动态路由?
📝 通俗解释
也就是**“热更新”。
以前改了路由规则(比如加个新服务),得重启网关,这期间服务就断了,用户会骂娘。
动态路由就是:你把配置写在 Nacos(配置中心)里,一修改,网关立马感知并生效**,不用重启。
就像给运行中的汽车换轮胎(虽然有点夸张,但意思就是业务不中断)。
在使用 Spring Cloud Gateway 的时候,官方文档提供的方案总是基于配置文件或代码配置的方式。
Spring Cloud Gateway 作为微服务的入口,需要尽量避免重启,而现在配置更改需要重启服务不能满足实际生产过程中的动态刷新、实时变更的业务需求,所以我们需要在 Spring Cloud Gateway 运行时动态配置网关。
实现动态路由的方式有很多种,其中一种推荐的方式是基于 Nacos 注册中心来做。 Spring Cloud Gateway 可以从注册中心获取服务的元数据(例如服务名称、路径等),然后根据这些信息自动生成路由规则。这样,当你添加、移除或更新服务实例时,网关会自动感知并相应地调整路由规则,无需手动维护路由配置。
其实这些复杂的步骤并不需要我们手动实现,通过 Nacos Server 和 Spring Cloud Alibaba Nacos Config 即可实现配置的动态变更,官方文档地址:https://github.com/alibaba/spring-cloud-alibaba/wiki/Nacos-config 。
Spring Cloud Gateway 的过滤器有哪些?
📝 通俗解释
过滤器就是**“拦截器”**,对请求做手脚的。
分两类:
- GatewayFilter(局部):只针对某一个路由生效。比如“只有支付接口才需要验签”。
- GlobalFilter(全局):针对所有请求生效。比如“所有请求都要记日志”、“所有请求都要做鉴权”。
过滤器 Filter 按照请求和响应可以分为两种:
- Pre 类型:在请求被转发到微服务之前,对请求进行拦截和修改,例如参数校验、权限校验、流量监控、日志输出以及协议转换等操作。
- Post 类型:微服务处理完请求后,返回响应给网关,网关可以再次进行处理,例如修改响应内容或响应头、日志输出、流量监控等。
另外一种分类是按照过滤器 Filter 作用的范围进行划分:
- GatewayFilter:局部过滤器,应用在单个路由或一组路由上的过滤器。标红色表示比较常用的过滤器。
- GlobalFilter:全局过滤器,应用在所有路由上的过滤器。
局部过滤器
📝 通俗解释
就像**“专用通道”**。
比如StripPrefix,把/api/user/list变成/user/list再发给后端。这是针对特定路径的特殊处理。
常见的局部过滤器如下图所示:

具体怎么用呢?这里有个示例,如果 URL 匹配成功,则去掉 URL 中的 “api”。
filters: #过滤器
- RewritePath=/api/(?<segment>.*),/$\{segment} # 将跳转路径中包含的 “api” 替换成空当然我们也可以自定义过滤器,本篇不做展开。
全局过滤器
📝 通俗解释
就像**“大门口的保安”**。
谁进谁出都得经过他。最典型的就是LoadBalancerClientFilter(负载均衡),它负责把lb://service-name变成实际的ip:port。
常见的全局过滤器如下图所示:

全局过滤器最常见的用法是进行负载均衡。配置如下所示:
spring:
cloud:
gateway:
routes:
- id: route_member # 第三方微服务路由规则
uri: lb://passjava-member # 负载均衡,将请求转发到注册中心注册的 passjava-member 服务
predicates: # 断言
- Path=/api/member/** # 如果前端请求路径包含 api/member,则应用这条路由规则
filters: #过滤器
- RewritePath=/api/(?<segment>.*),/$\{segment} # 将跳转路径中包含的api替换成空这里有个关键字 lb,用到了全局过滤器 LoadBalancerClientFilter,当匹配到这个路由后,会将请求转发到 passjava-member 服务,且支持负载均衡转发,也就是先将 passjava-member 解析成实际的微服务的 host 和 port,然后再转发给实际的微服务。
Spring Cloud Gateway 支持限流吗?
📝 通俗解释
支持,但有点简陋。
它自带了基于 Redis 的限流(令牌桶算法),能用,但配置起来稍微有点麻烦。
推荐方案:搭配 Sentinel。
Sentinel 是专业的流量控制组件,功能更强大,还有可视化界面,想怎么限就怎么限(QPS、线程数、流控效果等)。
Spring Cloud Gateway 自带了限流过滤器,对应的接口是 RateLimiter,RateLimiter 接口只有一个实现类 RedisRateLimiter (基于 Redis + Lua 实现的限流),提供的限流功能比较简易且不易使用。
从 Sentinel 1.6.0 版本开始,Sentinel 引入了 Spring Cloud Gateway 的适配模块,可以提供两种资源维度的限流:route 维度和自定义 API 维度。也就是说,Spring Cloud Gateway 可以结合 Sentinel 实现更强大的网关流量控制。
Spring Cloud Gateway 如何自定义全局异常处理?
📝 通俗解释
网关是入口,如果网关报错了(比如 404、503),直接把一大堆英文堆栈返给前端太难看了。
我们需要自定义异常处理,把异常捕获住,然后返回一个友好的 JSON,比如{"code": 500, "msg": "系统繁忙,请稍后再试"}。
做法是实现ErrorWebExceptionHandler接口,覆盖handle方法。
在 SpringBoot 项目中,我们捕获全局异常只需要在项目中配置 @RestControllerAdvice和 @ExceptionHandler就可以了。不过,这种方式在 Spring Cloud Gateway 下不适用。
Spring Cloud Gateway 提供了多种全局处理的方式,比较常用的一种是实现ErrorWebExceptionHandler并重写其中的handle方法。
@Order(-1)
@Component
@RequiredArgsConstructor
public class GlobalErrorWebExceptionHandler implements ErrorWebExceptionHandler {
private final ObjectMapper objectMapper;
@Override
public Mono<Void> handle(ServerWebExchange exchange, Throwable ex) {
// ...
}
}参考
- Spring Cloud Gateway 官方文档:https://cloud.spring.io/spring-cloud-gateway/reference/html/
- Creating a custom Spring Cloud Gateway Filter:https://spring.io/blog/2022/08/26/creating-a-custom-spring-cloud-gateway-filter
- 全局异常处理: https://zhuanlan.zhihu.com/p/347028665
