Spring Cloud Gateway 源码阅读 —— 请求处理与过滤器链
过滤器链是 Gateway 的"执行引擎":所有横切逻辑(鉴权、限流、改写、转发)都挂在这条链上。本文从源码拆解链的构建、排序与执行,以及 GlobalFilter 与 GatewayFilter 的组合规则。
FilteringWebHandler:过滤器链入口
路由匹配命中后,RoutePredicateHandlerMapping 返回 FilteringWebHandler 作为处理器,由 WebFlux 的 SimpleHandlerAdapter 调用其 handle():
java
// org.springframework.cloud.gateway.handler.FilteringWebHandler
public class FilteringWebHandler implements WebHandler {
private final List<GatewayFilter> globalFilters; // 所有 GlobalFilter 实例
public FilteringWebHandler(List<GlobalFilter> globalFilters) {
// 构造时把 GlobalFilter 包装成 GatewayFilter 适配器
this.globalFilters = loadFilters(globalFilters);
}
@Override
public Mono<Void> handle(ServerWebExchange exchange) {
Route route = exchange.getRequiredAttribute(GATEWAY_ROUTE_ATTR);
// 1. 取路由级过滤器
List<GatewayFilter> gatewayFilters = route.getFilters();
// 2. 合并:全局 + 路由级
List<GatewayFilter> all = new ArrayList<>(this.globalFilters);
all.addAll(gatewayFilters);
// 3. 排序(OrderedComparator,order 小者优先)
AnnotationAwareOrderComparator.sort(all);
// 4. 构建责任链并执行
return new DefaultGatewayFilterChain(all).filter(exchange);
}
}GatewayFilter 与 GlobalFilter 的组合
类型转换:GlobalFilter → GatewayFilter
GlobalFilter 不是 GatewayFilter,怎么合并?通过适配器包装:
java
private static List<GatewayFilter> loadFilters(List<GlobalFilter> filters) {
return filters.stream().map(filter -> {
GatewayFilterAdapter gatewayFilter = new GatewayFilterAdapter(filter);
// 沿用 GlobalFilter 的 order
if (filter instanceof Ordered) {
int order = ((Ordered) filter).getOrder();
gatewayFilter.setOrder(order);
}
return gatewayFilter;
}).collect(Collectors.toList());
}
// 适配器:委托给原 GlobalFilter
private static class GatewayFilterAdapter implements GatewayFilter, Ordered {
private final GlobalFilter delegate;
@Override public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
return this.delegate.filter(exchange, chain);
}
}组合规则小结
| 过滤器类型 | 来源 | 作用范围 | 参与排序 |
|---|---|---|---|
| GlobalFilter | Spring Bean(自动发现) | 所有请求 | 是(实现 Ordered) |
| GatewayFilter(路由级) | 路由配置的工厂生成 | 该路由 | 是(合并后统一排序) |
合并后统一排序,意味着 GlobalFilter 可以与路由过滤器交错执行——这是理解网关执行顺序的关键。
常用 GlobalFilter 及顺序
| 过滤器 | order | 职责 |
|---|---|---|
| RouteToRequestUrlFilter | 10000 | 计算请求转发 URL(lb:// 解析) |
| LoadBalancerClientFilter | 10100 | 负载均衡选实例,替换 URI |
| ReactiveLoadBalancerClientFilter | 10150 | 新版 LoadBalancer 实现 |
| WebsocketRoutingFilter | 2147483646 | WebSocket 代理 |
| NettyRoutingFilter | 2147483647 | HTTP 转发(最后执行) |
10000 RouteToRequestUrlFilter
→ 10100 LoadBalancerClientFilter(lb:// → http://ip:port)
→ ... 业务 GlobalFilter(鉴权、限流等)
→ 2147483647 NettyRoutingFilter(真正转发)DefaultGatewayFilterChain:责任链实现
核心代码
java
// org.springframework.cloud.gateway.handler.FilteringWebHandler.DefaultGatewayFilterChain
private static class DefaultGatewayFilterChain implements GatewayFilterChain {
private final List<GatewayFilter> filters;
private final int index;
public DefaultGatewayFilterChain(List<GatewayFilter> filters) {
this(filters, 0);
}
private DefaultGatewayFilterChain(List<GatewayFilter> filters, int index) {
this.filters = filters;
this.index = index;
}
@Override
public Mono<Void> filter(ServerWebExchange exchange) {
// 链未结束:执行下一个过滤器
if (this.index < filters.size()) {
GatewayFilter filter = this.filters.get(this.index);
// 关键:每次新建链(index+1),保证单向不可回溯
DefaultGatewayFilterChain chain =
new DefaultGatewayFilterChain(this.filters, this.index + 1);
return filter.filter(exchange, chain);
}
// 链结束:返回空 Mono(结束信号)
return Mono.empty();
}
}责任链特性
- 单向链:每个过滤器拿到"下一个链",不能回头
- 短路:过滤器不调用
chain.filter()即中断链路(鉴权失败直接返回 401) - 响应阶段:
chain.filter()返回的 Mono 完成后执行后置逻辑(.then()/doFinally())
请求与响应上下文:ServerWebExchange
整条链共享的上下文对象:
java
// org.springframework.web.server.ServerWebExchange
public interface ServerWebExchange {
ServerHttpRequest getRequest(); // 请求(可 mutate 修改)
ServerHttpResponse getResponse(); // 响应
Map<String, Object> getAttributes(); // 属性(跨过滤器共享)
Mono<Void> getPrincipal(); // 认证主体
// ...
}修改请求的标准方式
java
// 1. mutate 请求
ServerHttpRequest newRequest = exchange.getRequest().mutate()
.header("X-New-Header", "value")
.path("/new/path")
.build();
// 2. mutate exchange 并继续链
return chain.filter(exchange.mutate().request(newRequest).build());属性传递(跨过滤器共享数据)
java
// 前一个过滤器写入
exchange.getAttributes().put("startTime", System.currentTimeMillis());
// 后一个过滤器读取
long start = exchange.getAttribute("startTime");过滤器执行的三段式
每个过滤器可以有三个阶段的逻辑:
java
return chain.filter(exchange)
.then(Mono.fromRunnable(() -> {
// 阶段三:响应完成后(后置处理)
long cost = System.currentTimeMillis() - start;
log.info("耗时 {}", cost);
}))
.doOnError(ex -> {
// 异常处理
});阶段一:请求前逻辑(before)→ chain.filter()
阶段二:转发/下游执行(chain 递归调用)
阶段三:响应后逻辑(after,在 .then 中)自定义过滤器挂载点
全局过滤器(影响所有路由)
java
@Component
public class TraceGlobalFilter implements GlobalFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
// 前向:注入 TraceId
String traceId = UUID.randomUUID().toString().replace("-", "");
ServerHttpRequest req = exchange.getRequest().mutate()
.header("X-Trace-Id", traceId).build();
// 响应也加 TraceId
exchange.getResponse().getHeaders().add("X-Trace-Id", traceId);
return chain.filter(exchange.mutate().request(req).build());
}
@Override
public int getOrder() {
return -100; // 尽量靠前执行
}
}路由级过滤器(只影响指定路由)
yaml
- id: order-route
uri: lb://order-service
predicates: [ Path=/api/order/** ]
filters:
- AddRequestHeader=X-Trace-Id, abc完整执行时序
请求 → DispatcherHandler
→ RoutePredicateHandlerMapping(路由匹配)
→ FilteringWebHandler.handle()
→ 合并 [GlobalFilters, route.filters] + 排序
→ DefaultGatewayFilterChain.filter()
→ RouteToRequestUrlFilter(order 10000)→ 计算 URL
→ LoadBalancerClientFilter(order 10100)→ 选实例
→ 业务全局过滤器(鉴权/限流/日志)
→ NettyRoutingFilter(order MAX)→ 转发下游
→ 下游响应返回 → 链反向执行后置逻辑
→ 响应返回客户端关键源码文件索引
| 类 | 位置 |
|---|---|
| FilteringWebHandler | gateway-server/.../handler/FilteringWebHandler.java |
| DefaultGatewayFilterChain | FilteringWebHandler 内部类 |
| GlobalFilter | gateway-server/.../filter/GlobalFilter.java |
| GatewayFilter | gateway-server/.../filter/GatewayFilter.java |
| GatewayFilterChain | gateway-server/.../filter/GatewayFilterChain.java |
| RouteToRequestUrlFilter | gateway-server/.../filter/RouteToRequestUrlFilter.java |
| NettyRoutingFilter | gateway-server/.../filter/NettyRoutingFilter.java |
常见问题
- 过滤器执行顺序乱? 合并后统一按
Ordered排序;确认自定义过滤器实现Ordered并返回正确的 order。 - 过滤器里修改了请求但下游没生效? 必须用
exchange.mutate().request(newRequest).build()替换后继续chain.filter()。 - 鉴权失败怎么中断? 不调用
chain.filter(),设置响应状态码并exchange.getResponse().setComplete()。 - 响应阶段怎么拿耗时? 请求前记录 startTime 到 exchange 属性,
.then()中计算差值。