From a6716da742e243042b757a4030ddbf9899485d3c Mon Sep 17 00:00:00 2001 From: zhangjf Date: Fri, 20 Feb 2026 16:51:23 +0800 Subject: [PATCH] =?UTF-8?q?docs:=20=E9=97=AE=E9=A2=98=E6=B8=85=E5=8D=95?= =?UTF-8?q?=E6=96=B0=E5=A2=9E=E9=97=AE=E9=A2=9811-ContextInterceptor?= =?UTF-8?q?=E5=93=8D=E5=BA=94=E5=A4=B4=E6=9C=AA=E8=AE=BE=E7=BD=AEtraceId?= =?UTF-8?q?=E5=92=8CspanId?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- doc/开发问题清单.md | 104 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 104 insertions(+) diff --git a/doc/开发问题清单.md b/doc/开发问题清单.md index cbd277e..99242a0 100644 --- a/doc/开发问题清单.md +++ b/doc/开发问题清单.md @@ -20,6 +20,7 @@ | 8 | OpenFeign配置 | FeignClient硬编码URL导致Nacos服务发现失效 | 高 | 已解决 | | 9 | Nacos 配置 | Nacos 3.0 客户端缺少 username/password 认证配置 | 高 | 已解决 | | 10 | 连接池监控 | HikariMonitorConfig空指针异常 | 中 | 已解决 | +| 11 | 链路追踪 | ContextInterceptor响应头未设置traceId和spanId | 高 | 已解决 | --- @@ -666,6 +667,105 @@ public void monitorHikariPool() { --- +### 问题11:ContextInterceptor响应头未设置traceId和spanId + +#### 问题现象 +用户反馈API响应头中没有返回`X-Trace-Id`和`X-Span-Id`,导致无法通过响应头直接获取追踪标识进行问题排查。 + +```bash +# 预期响应头 +HTTP/1.1 200 OK +X-Trace-Id: abc123def456789abc123def456789ab +X-Span-Id: 1a2b3c4d5e6f7g8h + +# 实际响应头(缺失追踪标识) +HTTP/1.1 200 OK +Content-Type: application/json +``` + +#### 问题原因 +`ContextInterceptor.java`文件虽然在Git提交中包含了响应头设置代码,但文件实际内容与提交记录不符,缺少以下关键代码: + +```java +// 缺少的代码 +public static final String HEADER_SPAN_ID = "X-Span-Id"; + +// 生成 SpanId +String spanId = TraceContextHolder.getOrCreateSpanId(); + +// 在响应头中返回 traceId 和 spanId +response.setHeader(HEADER_TRACE_ID, traceId); +response.setHeader(HEADER_SPAN_ID, spanId); +``` + +#### 解决方案 + +**修复 `fund-common/src/main/java/com/fundplatform/common/web/ContextInterceptor.java`** + +```java +@Override +public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) { + // ... 其他代码 ... + + // 提取或生成 TraceId(全链路唯一标识) + String traceId = request.getHeader(HEADER_TRACE_ID); + if (traceId != null && !traceId.isEmpty()) { + TraceContextHolder.setTraceId(traceId); + } else { + traceId = TraceContextHolder.getOrCreateTraceId(); + } + + // 生成 SpanId(当前服务处理标识,每个请求唯一) + String spanId = TraceContextHolder.getOrCreateSpanId(); + + // 在响应头中返回 traceId 和 spanId,方便客户端追踪 + response.setHeader(HEADER_TRACE_ID, traceId); + response.setHeader(HEADER_SPAN_ID, spanId); + + // ... 其他代码 ... +} +``` + +**同时需要在 `TraceContextHolder.java` 中添加 SpanId 支持**: + +```java +private static final ThreadLocal SPAN_ID_HOLDER = new ThreadLocal<>(); +private static final String MDC_KEY_SPAN_ID = "spanId"; + +public static void setSpanId(String spanId) { + SPAN_ID_HOLDER.set(spanId); + MDC.put(MDC_KEY_SPAN_ID, spanId); +} + +public static String getSpanId() { + return SPAN_ID_HOLDER.get(); +} + +public static String getOrCreateSpanId() { + String spanId = SPAN_ID_HOLDER.get(); + if (spanId == null || spanId.isEmpty()) { + spanId = generateSpanId(); + setSpanId(spanId); + } + return spanId; +} + +public static String generateSpanId() { + return UUID.randomUUID().toString().replace("-", "").substring(0, 16); +} +``` + +#### 修复文件 +- `fund-common/src/main/java/com/fundplatform/common/context/TraceContextHolder.java` +- `fund-common/src/main/java/com/fundplatform/common/web/ContextInterceptor.java` + +#### 经验总结 +- **文件提交后需验证实际内容**,不能仅依赖Git提交记录 +- **代码审查时需检查文件实际内容**,确保修改确实生效 +- **响应头设置应在 preHandle 中完成**,确保所有请求都能返回追踪标识 + +--- + ## 预防措施清单 ### 前后端接口对接 @@ -697,6 +797,7 @@ public void monitorHikariPool() { | **FeignClient 配置** | **有注册中心时必须移除 url 属性,仅保留 name** | | **Nacos 3.0 认证** | **客户端必须配置 username 和 password(默认都是 nacos)** | | **定时任务资源检查** | **定时任务访问资源前需检查资源是否已初始化(如连接池)** | +| **链路追踪响应头** | **API响应必须返回X-Trace-Id和X-Span-Id,便于客户端追踪** | ### 功能开发流程 @@ -725,6 +826,8 @@ public void monitorHikariPool() { - `fund-report/src/main/java/com/fundplatform/report/feign/ProjectFeignClient.java` - 移除硬编码 URL,使用 Nacos 服务发现 - `fund-cust/src/main/java/com/fundplatform/cust/feign/SysServiceClient.java` - 移除硬编码 URL,使用 Nacos 服务发现 - `fund-*/src/main/resources/application.yml` - 为所有业务模块添加 Nacos 3.0 username/password 认证配置 +- `fund-common/src/main/java/com/fundplatform/common/context/TraceContextHolder.java` - 添加 SpanId 支持 +- `fund-common/src/main/java/com/fundplatform/common/web/ContextInterceptor.java` - 响应头设置 traceId 和 spanId **前端文件:** - `fund-admin/vite.config.ts` - 代理配置修复 @@ -749,6 +852,7 @@ public void monitorHikariPool() { | `服务发现失效` | FeignClient 硬编码 URL | 移除 url 属性,仅保留 name 使用 Nacos 发现 | | `Nacos 注册失败 (认证错误)` | 缺少 username/password 配置 | 在 discovery 节点添加 username 和 password | | `HikariPoolMXBean NullPointerException` | 定时任务执行时连接池未初始化 | 添加 poolMXBean 空值检查 | +| `响应头缺失X-Trace-Id/X-Span-Id` | ContextInterceptor未设置响应头 | 在preHandle中调用response.setHeader() | ---