Spring Cloud Gateway全局过滤器在网关过滤器后不执行问题求助
Spring Cloud Gateway自定义Vary全局过滤器在路由过滤器启用后不执行且返回500错误
问题重现
- 配置了三类过滤器:
- Vary全局过滤器:实现
GlobalFilter和Ordered,作为后置过滤器,order=-1,未启用路由过滤器时可正常执行 - CORS全局过滤器:前置过滤器,
order=0,执行正常 - TestGatewayFilter路由过滤器:通过YAML绑定到特定路由,
order=10,简化后仅调用chain.filter(exchange)
- Vary全局过滤器:实现
- 现象:启用路由过滤器后,Vary过滤器不执行且请求返回500;仅保留全局过滤器时,CORS和Vary均正常执行
相关代码
TestGatewayFilter实现
@Component public class TestGatewayFilter extends AbstractGatewayFilterFactory<TestGatewayFilter.Config> implements Ordered { public TestGatewayFilter() { super(Config.class); } @Override public GatewayFilter apply(Config config) { return (exchange, chain) -> { return chain.filter(exchange); }; } @Override public int getOrder() { return 10; } public static class Config { // 配置项 } }
YAML路由配置
spring: cloud: gateway: routes: - id: servicev1 uri: http://service-app:8888 predicates: - Path=/sgateway/service/v1/** filters: - name: TestGatewayFilter
Vary过滤器核心代码
@Override public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { return chain.filter(exchange) .then(Mono.fromRunnable(() -> addResponseHeaders(exchange.getRequest(),exchange.getResponse()))); }
原因分析
- 响应提交后修改头触发异常:路由过滤器执行完成并调用后端服务后,响应大概率已被提交(
response.isCommitted()=true),此时Vary过滤器在then回调中尝试修改响应头会抛出IllegalStateException,直接导致请求返回500,同时表现为Vary过滤器未执行(实际是执行时抛出了异常)。 - 过滤器顺序逻辑误解:Spring Cloud Gateway的过滤器按
order升序执行前置逻辑,按逆序执行后置逻辑(then回调)。Vary过滤器order=-1会比路由过滤器(order=10)更早进入执行链,其then回调会在路由过滤器的then之后执行,此时后端响应已完成提交。
解决方案
方案1:先检查响应状态再修改头
修改Vary过滤器的addResponseHeaders方法,仅在响应未提交时执行修改:
private void addResponseHeaders(ServerHttpRequest request, ServerHttpResponse response) { if (!response.isCommitted()) { // 你的Vary头添加逻辑,示例: response.getHeaders().add("Vary", "Accept, Accept-Encoding"); } }
方案2:通过响应装饰器在写入前修改头(推荐)
使用ServerHttpResponseDecorator包装响应,在响应写入客户端之前添加头,从根源避免响应提交后修改的问题:
@Override public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { ServerHttpResponse originalResponse = exchange.getResponse(); ServerHttpResponseDecorator decoratedResponse = new ServerHttpResponseDecorator(originalResponse) { @Override public Mono<Void> writeWith(Publisher<? extends DataBuffer> body) { addResponseHeaders(exchange.getRequest(), this); return super.writeWith(body); } @Override public Mono<Void> writeAndFlushWith(Publisher<? extends Publisher<? extends DataBuffer>> body) { addResponseHeaders(exchange.getRequest(), this); return super.writeAndFlushWith(body); } }; return chain.filter(exchange.mutate().response(decoratedResponse).build()); }
方案3:调整Vary过滤器的order值
将Vary过滤器的order设置为比所有路由过滤器更大的值(比如11),让它的后置逻辑在路由过滤器之前执行,此时响应大概率未被提交:
@Override public int getOrder() { return 11; // 大于路由过滤器的order=10 }
验证建议
- 开启DEBUG日志查看过滤器执行顺序和异常细节:
logging: level: org.springframework.cloud.gateway: DEBUG org.springframework.http.server.reactive: DEBUG - 检查日志中是否存在
Cannot modify headers once response has been committed类的异常,确认问题根源。
内容的提问来源于stack exchange,提问作者PastaLev
相关产品推荐
相关产品推荐

