Spring Cloud Gateway GlobalFilter中无法获取Trace ID(Brave+Zipkin)
问题:Spring Cloud Gateway后置过滤器中TraceContext为null,无法添加Trace ID到响应头
我编写了一个后置过滤器,尝试将Trace ID添加到响应头中,按相关方法操作后,TraceContext始终为null。
过滤器代码
@Slf4j @Configuration public class PostFilters { public static final String CORRELATION_ID = "X-CORRELATION-ID"; @Bean public GlobalFilter correlationIdPostFilter() { return(exchange, chain) -> chain.filter(exchange) .then(Mono.just(exchange)) .map(serverWebExchange -> { TraceContext traceContext = WebFluxSleuthOperators.currentTraceContext(serverWebExchange); log.info("Trace Context: {}", traceContext); if (traceContext != null) { serverWebExchange.getResponse().getHeaders().set(CORRELATION_ID, traceContext.traceId()); } return serverWebExchange; }) .then(); } }
依赖配置
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> <dependency> <groupId>io.micrometer</groupId> <artifactId>micrometer-tracing-bridge-brave</artifactId> </dependency> <dependency> <groupId>io.zipkin.reporter2</groupId> <artifactId>zipkin-reporter-brave</artifactId> </dependency> <dependency> <groupId>io.zipkin.reporter2</groupId> <artifactId>zipkin-sender-okhttp3</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-sleuth-instrumentation</artifactId> </dependency>
主类代码
@SpringBootApplication public class ApiGatewayApplication { public static void main(String[] args) { Hooks.enableAutomaticContextPropagation(); new SpringApplicationBuilder(ApiGatewayApplication.class) .web(WebApplicationType.REACTIVE) .run(args); } }
已确认上下文传播正常,日志和Zipkin中能看到跨服务的Trace ID。
解决方案
问题根源
chain.filter(exchange)执行完成后,Trace上下文已被清理,后续通过WebFluxSleuthOperators.currentTraceContext无法获取到有效上下文。
修复方案一:在请求处理回调中直接处理
使用doOnSuccess替代then(Mono.just(exchange)),确保在上下文未被清理时操作响应头:
@Slf4j @Configuration public class PostFilters { public static final String CORRELATION_ID = "X-CORRELATION-ID"; @Bean public GlobalFilter correlationIdPostFilter() { return (exchange, chain) -> chain.filter(exchange) .doOnSuccess(aVoid -> { TraceContext traceContext = WebFluxSleuthOperators.currentTraceContext(exchange); log.info("Trace Context: {}", traceContext); if (traceContext != null) { exchange.getResponse().getHeaders().set(CORRELATION_ID, traceContext.traceId()); } }); } }
修复方案二:提前保存Trace ID
在过滤器前置阶段获取Trace ID并存储到Exchange属性中,后置阶段直接取用:
@Slf4j @Configuration public class PostFilters { public static final String CORRELATION_ID = "X-CORRELATION-ID"; private static final String TRACE_ID_ATTR = "TRACE_ID_ATTR"; @Bean public GlobalFilter correlationIdPostFilter() { return (exchange, chain) -> { // 前置阶段保存Trace ID TraceContext traceContext = WebFluxSleuthOperators.currentTraceContext(exchange); if (traceContext != null) { exchange.getAttributes().put(TRACE_ID_ATTR, traceContext.traceId()); } return chain.filter(exchange) .doOnSuccess(aVoid -> { // 后置阶段取出Trace ID设置响应头 String traceId = exchange.getAttribute(TRACE_ID_ATTR); if (traceId != null) { exchange.getResponse().getHeaders().set(CORRELATION_ID, traceId); } }); }; } }
额外优化建议
如果使用Spring Cloud 2023.0.x及以上版本,可直接注入Tracer bean获取上下文:
@Autowired private Tracer tracer; // 在处理逻辑中调用 TraceContext traceContext = tracer.currentTraceContext().context();
内容的提问来源于stack exchange,提问作者Jacob L
相关产品推荐
相关产品推荐

