Spring Cloud Sleuth请求头缺失时如何初始化Baggage项
WebFlux 环境下 Baggage 字段缺省自动生成的最佳实现
你现有配置已经完成了x-fapi-interaction-id的跨服务传播注册,只需要补充入口请求的缺省值生成逻辑即可,核心要求是生成逻辑必须在链路上下文初始化完成前执行,避免出现Baggage写入过晚导致异步线程、子Span、下游服务拿不到值的问题。
实现步骤
- 保留你原有两个Baggage传播相关的Bean配置,不需要改动
- 新增
ObservationFilter组件(适配Spring Boot 2.7+ / 3.x 内置的Micrometer Tracing链路体系,也是WebFlux环境下最稳妥的实现方式),在HTTP入口请求的根Span刚创建时就检查字段值,缺失则自动生成。
完整配置代码
@Configuration public class FAPIAutoConfiguration { private static final String INTERACTION_ID = "x-fapi-interaction-id"; private final BaggageField fapiBaggageField = BaggageField.create(INTERACTION_ID); @Bean BaggagePropagationCustomizer baggagePropagationCustomizer() { return builder -> builder.add(SingleBaggageField.remote(fapiBaggageField)); } @Bean CorrelationScopeCustomizer correlationScopeCustomizer() { return builder -> builder.add(SingleCorrelationField.create(fapiBaggageField)); } @Bean ObservationFilter fapiInteractionIdGenerator(Tracer tracer) { return context -> { // 仅拦截服务端HTTP入口请求,避免内部调用、客户端请求场景重复生成ID if (context instanceof ServerRequestObservationContext serverCtx) { // 优先从已初始化的Baggage取值,不存在则直接从请求头读取 String interactionId = tracer.getBaggage(INTERACTION_ID).get(); if (interactionId == null || interactionId.isBlank()) { interactionId = serverCtx.getCarrier().getFirst(INTERACTION_ID); } // 两处都取不到值时,自动生成符合FAPI规范的UUID作为交互ID if (interactionId == null || interactionId.isBlank()) { interactionId = UUID.randomUUID().toString(); // 写入Baggage并绑定到当前作用域,自动透传给所有子Span、异步线程、下游服务 try (BaggageInScope ignored = tracer.createBaggageInScope(INTERACTION_ID, interactionId)) { // 按FAPI规范要求,将ID写入响应头返回给调用方 serverCtx.getResponse().addHeader(INTERACTION_ID, interactionId); } } } return context; }; } }
注意事项
- 别用普通
WebFilter实现生成逻辑:普通WebFilter默认执行顺序在链路追踪核心过滤器之后,此时根Span、MDC上下文已经初始化完,再写Baggage会出现入口日志打不上ID、异步线程拿不到值的问题。ObservationFilter是在观测上下文刚创建的时候执行,写进去的Baggage会自动带到所有子Span、异步线程、下游请求里,不会丢。 - 生成ID直接用标准UUID字符串就行,完全符合FAPI协议对
x-fapi-interaction-id的格式要求。 - 上面的实现自动兼容两种场景:请求头带了ID就直接透传,没带就自己生成,两种情况都会把ID写回响应头,符合FAPI的规范要求。
- 如果你用的是Spring Cloud 2020之前的旧版Sleuth,没有内置Micrometer Tracing,把
ObservationFilter换成自定义WebFilter就行,执行顺序设成Ordered.HIGHEST_PRECEDENCE + 10(比链路核心过滤器优先级低10位,保证上下文已经创建但还没开始向后传播),里面取值、生成、写Baggage的逻辑和上面完全一样。
内容的提问来源于stack exchange,提问作者Víctor Herraiz
相关产品推荐
相关产品推荐

