--- title: Spring Cloud Gateway常见问题总结 category: 分布式 --- > 本文重构完善自[6000 字 | 16 图 | 深入理解 Spring Cloud Gateway 的原理 - 悟空聊架构](https://mp.weixin.qq.com/s/XjFYsP1IUqNzWqXZdJn-Aw)这篇文章。 ## 什么是 Spring Cloud Gateway? 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。 ![](https://oss.javaguide.cn/github/javaguide/system-design/distributed-system/api-gateway/springcloud-gateway-%20demo.png) Spring Cloud Gateway 不仅提供统一的路由方式,并且基于 Filter 链的方式提供了网关基本的功能,例如:安全,监控/指标,限流。 Spring Cloud Gateway 和 Zuul 2.x 的差别不大,也是通过过滤器来处理请求。不过,目前更加推荐使用 Spring Cloud Gateway 而非 Zuul,Spring Cloud 生态对其支持更加友好。 - GitHub 地址: - 官网: ## Spring Cloud Gateway 的工作流程? Spring Cloud Gateway 的工作流程如下图所示: ![Spring Cloud Gateway 的工作流程](https://oss.javaguide.cn/github/javaguide/system-design/distributed-system/api-gateway/spring-cloud-gateway-workflow.png) 这是 Spring 官方博客中的一张图,原文地址:。 具体的流程分析: 1. **路由判断**:客户端的请求到达网关后,先经过 Gateway Handler Mapping 处理,这里面会做断言(Predicate)判断,看下符合哪个路由规则,这个路由映射后端的某个服务。 2. **请求过滤**:然后请求到达 Gateway Web Handler,这里面有很多过滤器,组成过滤器链(Filter Chain),这些过滤器可以对请求进行拦截和修改,比如添加请求头、参数校验等等,有点像净化污水。然后将请求转发到实际的后端服务。这些过滤器逻辑上可以称作 Pre-Filters,Pre 可以理解为“在...之前”。 3. **服务处理**:后端服务会对请求进行处理。 4. **响应过滤**:后端处理完结果后,返回给 Gateway 的过滤器再次做处理,逻辑上可以称作 Post-Filters,Post 可以理解为“在...之后”。 5. **响应返回**:响应经过过滤处理后,返回给客户端。 总结:客户端的请求先通过匹配规则找到合适的路由,就能映射到具体的服务。然后请求经过过滤器处理后转发给具体的服务,服务处理后,再次经过过滤器处理,最后返回给客户端。 ## Spring Cloud Gateway 的断言是什么? 断言(Predicate)这个词听起来极其深奥,它是一种编程术语,我们生活中根本就不会用它。说白了它就是对一个表达式进行 if 判断,结果为真或假,如果为真则做这件事,否则做那件事。 在 Gateway 中,如果客户端发送的请求满足了断言的条件,则映射到指定的路由器,就能转发到指定的服务上进行处理。 断言配置的示例如下,配置了两个路由规则,有一个 predicates 断言配置,当请求 url 中包含 `api/thirdparty`,就匹配到了第一个路由 `route_thirdparty`。 ![断言配置示例](https://oss.javaguide.cn/github/javaguide/system-design/distributed-system/api-gateway/spring-cloud-gateway-predicate-example.png) 常见的路由断言规则如下图所示: ![Spring Cloud GateWay 路由断言规则](https://oss.javaguide.cn/github/javaguide/system-design/distributed-system/api-gateway/spring-cloud-gateway-predicate-rules.png) ## Spring Cloud Gateway 的路由和断言是什么关系? Route 路由和 Predicate 断言的对应关系如下:: ![路由和断言的对应关系](https://oss.javaguide.cn/github/javaguide/system-design/distributed-system/api-gateway/spring-cloud-gateway-predicate-route.png) - **一对多**:一个路由规则可以包含多个断言。如上图中路由 Route1 配置了三个断言 Predicate。 - **同时满足**:如果一个路由规则中有多个断言,则需要同时满足才能匹配。如上图中路由 Route2 配置了两个断言,客户端发送的请求必须同时满足这两个断言,才能匹配路由 Route2。 - **第一个匹配成功**:如果一个请求可以匹配多个路由,则映射第一个匹配成功的路由。如上图所示,客户端发送的请求满足 Route3 和 Route4 的断言,但是 Route3 的配置在配置文件中靠前,所以只会匹配 Route3。 ## Spring Cloud Gateway 如何实现动态路由? 在使用 Spring Cloud Gateway 的时候,官方文档提供的方案总是基于配置文件或代码配置的方式。 Spring Cloud Gateway 作为微服务的入口,需要尽量避免重启,而现在配置更改需要重启服务不能满足实际生产过程中的动态刷新、实时变更的业务需求,所以我们需要在 Spring Cloud Gateway 运行时动态配置网关。 实现动态路由的方式有很多种,其中一种推荐的方式是基于 Nacos 注册中心来做。 Spring Cloud Gateway 可以从注册中心获取服务的元数据(例如服务名称、路径等),然后根据这些信息自动生成路由规则。这样,当你添加、移除或更新服务实例时,网关会自动感知并相应地调整路由规则,无需手动维护路由配置。 其实这些复杂的步骤并不需要我们手动实现,通过 Nacos Server 和 Spring Cloud Alibaba Nacos Config 即可实现配置的动态变更,官方文档地址: 。 ## Spring Cloud Gateway 的过滤器有哪些? 过滤器 Filter 按照请求和响应可以分为两种: - **Pre 类型**:在请求被转发到微服务之前,对请求进行拦截和修改,例如参数校验、权限校验、流量监控、日志输出以及协议转换等操作。 - **Post 类型**:微服务处理完请求后,返回响应给网关,网关可以再次进行处理,例如修改响应内容或响应头、日志输出、流量监控等。 另外一种分类是按照过滤器 Filter 作用的范围进行划分: - **GatewayFilter**:局部过滤器,应用在单个路由或一组路由上的过滤器。标红色表示比较常用的过滤器。 - **GlobalFilter**:全局过滤器,应用在所有路由上的过滤器。 ### 局部过滤器 常见的局部过滤器如下图所示: ![](https://oss.javaguide.cn/github/javaguide/system-design/distributed-system/api-gateway/spring-cloud-gateway-gatewayfilters.png) 具体怎么用呢?这里有个示例,如果 URL 匹配成功,则去掉 URL 中的 “api”。 ```yaml filters: #过滤器 - RewritePath=/api/(?.*),/$\{segment} # 将跳转路径中包含的 “api” 替换成空 ``` 当然我们也可以自定义过滤器,本篇不做展开。 ### 全局过滤器 常见的全局过滤器如下图所示: ![](https://oss.javaguide.cn/github/javaguide/system-design/distributed-system/api-gateway/spring-cloud-gateway-globalfilters.png) 全局过滤器最常见的用法是进行负载均衡。配置如下所示: ```yaml spring: cloud: gateway: routes: - id: route_member # 第三方微服务路由规则 uri: lb://passjava-member # 负载均衡,将请求转发到注册中心注册的 passjava-member 服务 predicates: # 断言 - Path=/api/member/** # 如果前端请求路径包含 api/member,则应用这条路由规则 filters: #过滤器 - RewritePath=/api/(?.*),/$\{segment} # 将跳转路径中包含的api替换成空 ``` 这里有个关键字 `lb`,用到了全局过滤器 `LoadBalancerClientFilter`,当匹配到这个路由后,会将请求转发到 passjava-member 服务,且支持负载均衡转发,也就是先将 passjava-member 解析成实际的微服务的 host 和 port,然后再转发给实际的微服务。 ## Spring Cloud Gateway 支持限流吗? 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 如何自定义全局异常处理? 在 SpringBoot 项目中,我们捕获全局异常只需要在项目中配置 `@RestControllerAdvice`和 `@ExceptionHandler`就可以了。不过,这种方式在 Spring Cloud Gateway 下不适用。 Spring Cloud Gateway 提供了多种全局处理的方式,比较常用的一种是实现`ErrorWebExceptionHandler`并重写其中的`handle`方法。 ```java @Order(-1) @Component @RequiredArgsConstructor public class GlobalErrorWebExceptionHandler implements ErrorWebExceptionHandler { private final ObjectMapper objectMapper; @Override public Mono handle(ServerWebExchange exchange, Throwable ex) { // ... } } ``` ## 参考 - Spring Cloud Gateway 官方文档: - Creating a custom Spring Cloud Gateway Filter: - 全局异常处理: