TraceId如何在Spring-Cloud微服务的REST调用中传递

作者:青鱼入云日期:2025/10/26

文章目录

      • 推荐方案:基于Spring Cloud Sleuth(无侵入,官方推荐)
          • 1. 集成Sleuth
            * 2. 核心原理
            * 3. 日志配置(输出traceId)
            * 4. 验证
        • 自定义实现方案(不依赖Sleuth,了解原理)
          • 1. 定义常量(统一Header键)
            * 2. 发送端:通过拦截器传递traceId
            * * (1)RestTemplate调用场景
            * (2)Feign调用场景
            * 3. 接收端:通过过滤器提取traceId并设置到MDC
        • 关键注意事项

在Spring Cloud微服务中,REST接口调用的traceId传递核心是通过HTTP请求头(Header) 携带traceId,结合拦截器(发送端)和过滤器(接收端)实现自动传递,且不侵入业务代码。

推荐方案:基于Spring Cloud Sleuth(无侵入,官方推荐)

Spring Cloud Sleuth是Spring官方的分布式追踪组件,默认已实现traceId的生成、传递和MDC绑定,无需手动编码,完全无侵入。

1. 集成Sleuth

在微服务的pom.xml中引入依赖(以Spring Boot 2.x为例):

1<dependency>
2    <groupId>org.springframework.cloud</groupId>
3    <artifactId>spring-cloud-starter-sleuth</artifactId>
4</dependency>
5
2. 核心原理
  • 发送端:Sleuth会自动拦截RestTemplateFeignClient等HTTP调用,将当前线程MDC中的traceId(默认键为X-B3-TraceId)添加到HTTP请求头中。
  • 接收端:Sleuth会拦截HTTP请求,从请求头中提取X-B3-TraceId,自动设置到当前线程的MDC中(键为traceId),供日志框架使用。
  • 自动生成:若当前线程无traceId(如请求入口),Sleuth会自动生成全局唯一的traceId
3. 日志配置(输出traceId)

logback-spring.xml(或其他日志配置文件)中,通过%X{traceId}占位符输出traceId

1<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
2    <encoder>
3        <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%X{traceId}] [%thread] %-5level %logger{50} - %msg%n</pattern>
4    </encoder>
5</appender>
6
4. 验证
  • 服务A调用服务B的REST接口时,Sleuth会自动在请求头中添加X-B3-TraceId
  • 服务B的日志中会包含与服务A相同的traceId,实现全链路关联。

自定义实现方案(不依赖Sleuth,了解原理)

若需自定义traceId传递逻辑(如自定义Header键、生成规则),可通过发送端拦截器接收端过滤器实现。

1. 定义常量(统一Header键)
1public class TraceConstant {
2    // 自定义traceId在HTTP头中的键
3    public static final String TRACE_ID_HEADER = "X-Trace-Id";
4    // MDC中的键
5    public static final String TRACE_ID_MDC_KEY = "traceId";
6}
7
2. 发送端:通过拦截器传递traceId

发送端(调用其他服务的微服务)需要在HTTP请求发送前,将当前MDC的traceId放入请求头。

(1)RestTemplate调用场景

配置RestTemplate时添加拦截器:

1import org.springframework.context.annotation.Bean;
2import org.springframework.context.annotation.Configuration;
3import org.springframework.http.HttpHeaders;
4import org.springframework.http.HttpRequest;
5import org.springframework.http.client.ClientHttpRequestExecution;
6import org.springframework.http.client.ClientHttpRequestInterceptor;
7import org.springframework.http.client.ClientHttpResponse;
8import org.springframework.web.client.RestTemplate;
9import org.slf4j.MDC;
10import java.io.IOException;
11import java.util.UUID;
12
13@Configuration
14public class RestTemplateConfig {
15
16    @Bean
17    public RestTemplate restTemplate() {
18        RestTemplate restTemplate = new RestTemplate();
19        // 添加自定义拦截器,传递traceId
20        restTemplate.getInterceptors().add(new TraceIdInterceptor());
21        return restTemplate;
22    }
23
24    // 自定义拦截器
25    public static class TraceIdInterceptor implements ClientHttpRequestInterceptor {
26        @Override
27        public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {
28            // 1. 获取当前MDC的traceId,若不存在则生成
29            String traceId = MDC.get(TraceConstant.TRACE_ID_MDC_KEY);
30            if (traceId == null) {
31                traceId = generateTraceId();
32            }
33            // 2. 将traceId添加到请求头
34            HttpHeaders headers = request.getHeaders();
35            headers.add(TraceConstant.TRACE_ID_HEADER, traceId);
36            // 3. 继续执行请求
37            return execution.execute(request, body);
38        }
39
40        private String generateTraceId() {
41            return UUID.randomUUID().toString().replace("-", "");
42        }
43    }
44}
45
(2)Feign调用场景

通过RequestInterceptor拦截Feign请求,添加traceId到请求头:

1import feign.RequestInterceptor;
2import feign.RequestTemplate;
3import org.springframework.context.annotation.Bean;
4import org.springframework.context.annotation.Configuration;
5import org.slf4j.MDC;
6import java.util.UUID;
7
8@Configuration
9public class FeignConfig {
10
11    @Bean
12    public RequestInterceptor traceIdRequestInterceptor() {
13        return new RequestInterceptor() {
14            @Override
15            public void apply(RequestTemplate template) {
16                // 1. 获取或生成traceId
17                String traceId = MDC.get(TraceConstant.TRACE_ID_MDC_KEY);
18                if (traceId == null) {
19                    traceId = UUID.randomUUID().toString().replace("-", "");
20                }
21                // 2. 添加到Feign请求头
22                template.header(TraceConstant.TRACE_ID_HEADER, traceId);
23            }
24        };
25    }
26}
27
3. 接收端:通过过滤器提取traceId并设置到MDC

接收端(被调用的微服务)需要从HTTP请求头中提取traceId,设置到MDC,并在请求结束后清除。

1import org.springframework.stereotype.Component;
2import org.springframework.web.servlet.HandlerInterceptor;
3import org.slf4j.MDC;
4import javax.servlet.http.HttpServletRequest;
5import javax.servlet.http.HttpServletResponse;
6
7@Component
8public class TraceIdInterceptor implements HandlerInterceptor {
9
10    @Override
11    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
12        // 1. 从请求头提取traceId
13        String traceId = request.getHeader(TraceConstant.TRACE_ID_HEADER);
14        // 2. 若不存在,可生成新的(如入口服务)
15        if (traceId == null) {
16            traceId = generateTraceId();
17        }
18        // 3. 设置到MDC
19        MDC.put(TraceConstant.TRACE_ID_MDC_KEY, traceId);
20        return true;
21    }
22
23    @Override
24    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
25        // 4. 请求处理完成后清除MDC(关键:避免线程池复用导致的残留)
26        MDC.remove(TraceConstant.TRACE_ID_MDC_KEY);
27    }
28
29    private String generateTraceId() {
30        return UUID.randomUUID().toString().replace("-", "");
31    }
32}
33

注册拦截器(确保生效):

1import org.springframework.context.annotation.Configuration;
2import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
3import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
4import javax.annotation.Resource;
5
6@Configuration
7public class WebMvcConfig implements WebMvcConfigurer {
8
9    @Resource
10    private TraceIdInterceptor traceIdInterceptor;
11
12    @Override
13    public void addInterceptors(InterceptorRegistry registry) {
14        // 拦截所有请求
15        registry.addInterceptor(traceIdInterceptor).addPathPatterns("/**");
16    }
17}
18

关键注意事项

  1. 优先级:推荐使用Spring Cloud Sleuth,它与Spring Cloud生态(如Zipkin、Feign、Gateway)无缝集成,支持更复杂的链路追踪(如spanId、调用耗时)。
  2. 入口服务处理:对于整个链路的第一个服务(如网关),若请求头中无traceId,需自动生成(Sleuth或自定义拦截器均会处理)。
  3. 线程安全:接收端必须在afterCompletion中清除MDC,避免Tomcat线程池复用导致traceId串用。
  4. 网关传递:若使用Spring Cloud Gateway,需确保网关也配置了traceId传递(Sleuth对Gateway有原生支持,自定义方案需通过GlobalFilter实现)。

通过以上方式,可在Spring Cloud微服务的REST调用中实现traceId的自动传递,全链路日志将包含相同的traceId,便于问题追踪。


TraceId如何在Spring-Cloud微服务的REST调用中传递》 是转载文章,点击查看原文


相关推荐


Python 的内置函数 classmethod
IMPYLH2025/10/23

Python 内建函数列表 > Python 的内置函数 classmethod Python 的内置函数 classmethod 是一个装饰器,用于将一个方法标记为类方法。类方法属于类本身,而不是类的实例,因此可以在不创建实例的情况下直接通过类名调用。 def classmethod(fn): ''' 把一个方法封装成类方法 :param fn: 要封装的方法 :return: 封装后的方法 ''' 使用 @classmethod 装饰器来定义


攻防世界—easyupload
风语者日志2025/10/22

知识点补充 .user.ini php.ini是php的一个全局配置文件,对整个web服务起作用;而.user.ini和.htaccess一样是目录的配置文件,.user.ini就是用户自定义的一个php.ini,我们可以利用这个文件来构造后门和隐藏后门。 常用配置 auto_prepend_file = <filename> //包含在文件头 auto_append_file = <filename> //包含在文件尾 一句话木马变种 这里的题目由


数据结构(顺序表和链表)
泡泡鱼(敲代码中)2025/10/21

数据结构(题) 一、顺序表 1、移除元素   int removeElement(int* nums, int numsSize, int val) {     int dst = 0;     int src = 0;     while(src<numsSize)     {         if(nums[src]!=val)         {             nums[dst]=nums[src];             dst++;     


运放的 Input Offset Drift(输入失调漂移)
Heismk2025/10/19

Input Offset Drift(输入失调漂移)是衡量运算放大器(或其他精密放大器件)性能的关键指标,用于描述温度变化时输入失调电压的变化率,直接反映器件在温度波动环境下的稳定性。 核心定义 输入失调漂移指的是:当环境温度每变化 1℃ 时,运放的**输入失调电压(Input Offset Voltage)**所发生的变化量,单位通常为 μV/℃(微伏每摄氏度)或 nV/℃(纳伏每摄氏度)。 输入失调电压(Vos):理想运放输入短路时输出应为 0,但实际器件因内部工艺差异,需在输入端施加一个微


Compose 自定义布局和图形
Best_Jerry2025/10/18

Advanced layout concepts - MAD Skills Compose 提供各种开箱即用型解决方案,可帮助您快速轻松地从头开始构建界面。但是,如果您需要更进一步,以实现完全自定义的界面,该怎么办?详细了解高级布局概念,以便自行构建自定义布局,让您的设计实现更上一层楼。 1. Advanced Layout Concepts Layout 这一术语在 Compose 中有多种含义: 以下是每种含义的相关解释: 2. Layout phase and constraint


告别加班!这些数组操作技巧让前端开发效率翻倍
良山有风来2025/10/17

你是不是经常遇到这样的场景:产品经理扔过来一堆数据,要你快速处理展示;后端返回的数组结构复杂,需要层层筛选过滤;明明很简单的数据操作,却要写一大堆循环和判断... 别担心!今天这篇干货,就是来拯救你的。我将带你系统掌握JavaScript数组和对象的核心操作,学完立刻就能用在实际项目中。相信我,掌握这些技巧后,你的开发效率至少提升一倍! 数组基础:从创建到遍历 让我们从最基础的数组操作开始。数组就像是一个数据容器,能帮我们有序地存放各种信息。 创建数组有两种常用方式。第一种是用方括号,这是最简洁


阿里云负载均衡SLB的使用参考:创建阿里云ECS实例操作
熙客2025/10/15

目录 一、背景知识 1.1 概念 1.2 负载均衡类型选择 1.3 核心功能与工作原理 1.4 配置负载均衡的注意事项 二、传统型负载均衡CLB的使用示例 2.1 创建3个ECS实例 2.2 安装nginx 2.3 创建负载均衡CLB 2.4 负载均衡配置 2.5 负载均衡检验 一、背景知识 1.1 概念 阿里云负载均衡能将访问流量分发到后端多台云服务器上,提升应用系统的服务能力和高可用性。它主要包含以下三种产品: 特性维度CLB(传统型负载均衡)ALB(应


NineData云原生智能数据管理平台新功能发布|2025年9月版
NineData2025/10/14

本月共发布 17 项更新,其中重点发布 6 项、功能优化 11 项。 重点发布 数据库 DevOps - SQL 任务事务执行 SQL 任务支持以事务方式执行。在 DML 语句执行失败后自动回滚整个任务,确保执行原子性与一致性。 数据库 DevOps - 数据脱敏与敏感扫描 敏感数据保护模块新增支持 PostgreSQL、SQL Server、Oracle 数据源的自动扫描与脱敏,帮助企业更全面地识别并防护敏感信息。 数据库 DevOps - ER 图增强 ER 图现


Flutter - Melos Pub workspaces 实践
LinXunFeng2025/10/13

欢迎关注微信公众号:FSA全栈行动 👋 一、前言 为解决 App 代码臃肿、编译耗时的问题,我们进行了分包重构,核心思路如下: 业务分包:将不同业务线的代码拆分成独立的包,开发者只需聚焦于各自包内的 example 工程进行开发,从而提升编译和运行效率。 功能沉淀:把跨业务复用的功能(包括基础业务和非业务功能)也抽离成独立的包,逐步让主 App 轻量化为一个“空壳”,负责集成所有模块。 依赖管理:业务包之间使用 git 依赖,指向 master 分支;而非业务的功能包则发布到自建的 unp


业务流程建模标准(BPMN)
deepdata_cn2025/10/11

在数字化转型浪潮中,企业对业务流程的可视化、标准化与自动化需求日益迫切。BPMN(Business Process Model and Notation,业务流程建模符号) 作为全球通用的业务流程建模标准,通过统一的图形语言打破了“业务人员说不清楚、IT人员看不懂”的沟通壁垒,成为连接业务需求与技术实现的核心桥梁。 一、BPMN的起源与发展 在BPMN出现前,企业建模缺乏统一规范:有的用流程图(Flowchart),有的用UML活动图,甚至有的用手绘草图——不同角色对同一流程的理解差异巨大,导致

首页编辑器站点地图

Copyright © 2025 聚合阅读

License: CC BY-SA 4.0