Spring Cloud Gateway 的工作原理是什么?
简化版
Gateway 的核心模型是 Route、Predicate、Filter:Predicate 判断请求匹配哪条路由,Filter 在转发前后修改请求、响应或执行认证限流,Route 的 URI 决定目标服务。常见 Server WebFlux 版本基于响应式链路,过滤器中执行阻塞操作会占住事件循环并拖慢大量请求。
详细版
请求进入 Gateway 后,路由映射器寻找首条匹配 Route,将全局过滤器和该路由过滤器按顺序组成链,执行 pre 阶段后由路由过滤器发送下游请求,再逆序执行 post 阶段。lb://order-service 会借助 Spring Cloud LoadBalancer 从服务实例中选择目标。
网关适合统一认证、路由、灰度、限流、跨域和观测,但不应承载复杂业务编排。重写路径、读取请求体和重试都要谨慎:请求体可能只能消费一次,非幂等请求重试可能重复写入。
完整版教学
一、Route 的三个核心元素
spring:
cloud:
gateway:
routes:
- id: order-route
uri: lb://order-service
predicates:
- Path=/api/orders/**
filters:
- StripPrefix=1
id 用于标识路由,Predicate 决定是否匹配,Filter 改写调用过程,uri 指定目标。多个 Predicate 通常需要同时满足;路由顺序不当时,宽泛规则可能先吞掉更具体的路径。
| 元素 | 含义 | 常见例子 | 面试重点 |
|---|---|---|---|
| Route | 一条路由规则 | id、uri、predicates、filters | 匹配成功后才进入对应过滤链 |
| Predicate | 匹配条件 | Path、Host、Method、Header | 多个条件组合决定是否命中 |
| Filter | 前后置处理 | StripPrefix、AddRequestHeader、Retry | 分 pre 和 post 阶段 |
| URI | 转发目标 | lb://order-service、http://host | lb:// 会走服务发现和负载均衡 |
| Order | 执行顺序 | Ordered 接口或配置顺序 | 宽泛规则和全局过滤器尤其要注意 |
Gateway 的核心不是「转发 HTTP」这么简单,而是按 Route 匹配请求,再把全局过滤器和路由过滤器合并成有序链路。
二、过滤器链如何执行
GlobalFilter 对匹配路由的请求普遍生效,GatewayFilter 属于某条路由。二者会合并并按 Ordered 排序:高优先级过滤器更早执行 pre,调用下一个过滤器返回后又更晚执行 post。
Filter A pre
-> Filter B pre
-> 下游请求
<- 下游响应
<- Filter B post
<- Filter A post
理解调用栈回程,才能正确放置响应头、耗时统计和异常清理逻辑。如果 A 用来记录总耗时,B 用来鉴权,那么 A 的 pre 可以先记录开始时间,B 在内部完成鉴权和转发,响应回来后 A 的 post 再计算耗时。这个顺序和 Servlet Filter 的思路相似,但在 WebFlux 里表现为响应式链路。
三、响应式线程模型的边界
Gateway Server WebFlux 常运行在 Reactor Netty 事件循环上,少量线程负责大量连接。过滤器中直接调用阻塞数据库、同步 HTTP 或长时间计算,会阻塞事件循环,使不相关请求一起排队。
一个粗略例子:如果网关只有 8 个事件循环线程,而某个过滤器对每个请求阻塞 200ms,那么 8 个并发请求就能把事件循环全部占住,后续请求即使只是静态路由也要排队。响应式网关的吞吐优势来自非阻塞链路,不能把它当成普通业务线程池使用。
阻塞工作应避免放在网关;确实无法避免时要明确切换到受控调度器并限制并发。当前 Spring Cloud Gateway 也提供 Server MVC 方向,选择配置与扩展 API 时必须确认使用的是哪种变体,不能混用教程。
四、服务发现与负载均衡
lb://service-name 不是 DNS 地址。Gateway 的 LoadBalancer 过滤器解析服务名、选择 ServiceInstance,再把请求转发到实际 host 和 port。找不到实例时会产生相应错误响应,具体状态行为可按版本配置。
注册中心列表可能短暂陈旧,所以网关仍需连接超时、响应超时、熔断和监控,不能认为“发现成功”就等于下游健康。
五、限流、重试与请求体
RequestRateLimiter 可结合限流实现按用户、IP 或租户控制速率;键解析必须稳定,并防止攻击者制造无限高基数键。限流拒绝码、配额和突发容量应形成明确 API 契约。
请求体在响应式流中不能任意重复读取,验签或日志需要使用框架支持的缓存/修改机制,并限制体积。Retry 只适合可安全重放的请求,支付或创建类 POST 必须先具备业务幂等。
六、网关的职责边界
统一入口适合处理跨服务公共策略,但把聚合查询、数据库访问和复杂业务都塞进 Gateway,会形成新的单体瓶颈。业务编排应进入专门的聚合服务或 BFF,网关保持轻量和可水平扩展。
例如认证、跨域、灰度路由、统一限流、链路追踪注入适合放在网关;订单聚合查询、库存扣减、支付状态推进不适合放在网关。后者属于业务编排,应该进入业务服务或 BFF,否则网关会越来越重,扩容和排障都会变困难。
七、常见误区与追问
- 误区:Gateway 就是 Nginx 的 Java 版替代品。 Gateway 更贴近 Spring Cloud 生态,擅长服务发现、过滤器扩展和应用层策略;Nginx 更常用于高性能静态代理、TLS、四七层入口等场景。
- 误区:过滤器顺序只影响 pre 阶段。 高优先级过滤器 pre 更早执行,post 往往更晚返回,耗时统计和异常处理要按回程理解。
- 误区:
lb://表示直接 DNS 解析。 它会通过 Spring Cloud LoadBalancer 按服务名选择注册中心里的 ServiceInstance,再重建真实请求地址。 - 误区:WebFlux 网关里阻塞一点没关系。 事件循环线程数量少,阻塞操作会拖慢大量无关连接,应该避免同步 IO 和长计算。
- 追问:Gateway 适合放业务逻辑吗? 它适合统一认证、路由、限流、灰度和观测,不适合承载复杂业务编排和数据库访问。
- 追问:为什么读取请求体要谨慎? 响应式请求体是流式数据,默认不能随意多次消费,日志、验签和重写都要用框架支持的缓存机制并限制大小。
八、加强记忆
Spring Cloud Gateway 要按「Route、Predicate、Filter、URI、Order」记忆:Predicate 判断请求命中哪条 Route,Filter 在转发前后做统一处理,URI 决定目标,lb:// 会接入服务发现和负载均衡。过滤器链是 pre 顺序进入、post 回程返回;WebFlux 版本最怕阻塞事件循环,限流、重试、请求体缓存和业务编排都要守住网关边界。