Spring MVC 与 traceId 规范

reference
2026年7月20日2 min read245 words

Updated 2026年7月20日

Spring MVC 与 traceId 规范

适用场景

新增或修改 Controller、REST 接口、请求响应 DTO、全局异常、CORS、日志、审计、下游 HTTP 调用或链路跟踪时加载。

MVC 分层

  • HTTP 接口使用 @RestController;路径、HTTP 方法和状态码表达协议语义,不用统一 POST 代替所有操作。
  • Controller 只做 DTO 校验、协议转换和调用应用服务,不写业务规则、事务、数据访问或供应商调用。
  • 应用服务负责用例编排和事务边界;领域服务负责可测试的业务决策;Repository/Client 分别负责持久化和外部协议适配。
  • 请求/响应 DTO 与领域模型分离;转换逻辑放在所属边界附近,简单转换直接写清楚,不为单个 DTO 引入映射框架。
  • API 返回明确 HTTP 状态和结构化 JSON;不使用“永远 200 + 业务 code”掩盖协议错误。

traceId 传输契约

统一名称如下,不允许各接口自行命名:

位置 名称
HTTP 请求头 X-Trace-Id
HTTP 响应头 X-Trace-Id
MDC key traceId
错误响应字段 traceId
Servlet request attribute traceId
  • 前端所有 HTTP 方法通过同一个请求客户端或拦截器写入 X-Trace-Id,页面和业务组件不得重复拼接请求头。
  • 前端使用 crypto.randomUUID() 为一次请求生成 traceId;同一次自动重试沿用原值。后端调用下游服务时继续传递当前有效值。
  • traceId 只用于关联日志和审计,不作为身份、权限、幂等键或业务主键。
  • 跨域场景必须允许请求头 X-Trace-Id,并通过 Access-Control-Expose-Headers 暴露同名响应头;CORS 只开放实际前端来源,不使用带凭据的通配来源。

后端统一接收

  • 只允许一个继承 OncePerRequestFilter 的 traceId 过滤器统一接收请求头;核心方法为 doFilterInternal(...)
  • Controller 不重复声明 @RequestHeader("X-Trace-Id"),Service 方法也不为日志目的层层增加 traceId 参数。
  • 过滤器按以下顺序处理:
    1. 读取 X-Trace-Id
    2. 接受 8 至 64 位的字母、数字、点、下划线或连字符;空值、超长值、空白和控制字符均视为非法。
    3. 缺失或非法时使用 UUID.randomUUID().toString() 生成新值,不因链路字段缺失拒绝业务请求。
    4. 将有效值写入 request attribute、MDC 和 X-Trace-Id 响应头,再调用过滤器链。
    5. finally 中删除 MDC 的 traceId,防止线程复用造成串号。
  • header 名、MDC key 和校验规则各保留一个常量来源,不在过滤器、异常处理器和客户端拦截器中复制字符串。
  • 健康检查、静态资源和错误分派也必须返回有效 traceId;确需排除路径时先证明该路径不产生日志或审计记录。

日志、错误与审计

  • 日志格式统一包含 MDC 的 traceId;业务日志使用参数化日志,不拼接用户输入,不记录令牌、完整支付信息或不必要的供应商敏感字段。
  • @RestControllerAdvice 从 request attribute 取得当前 traceId 并写入错误响应,不重新生成。
  • 审计记录在应用边界显式保存当前 traceId;领域模型和纯决策服务不得依赖 HttpServletRequest、MDC 或静态请求上下文。
  • 下游 HTTP 客户端使用一个统一拦截器传递 X-Trace-Id,不得由每个 Client 方法手写。
  • 使用 @Async、线程池、消息队列或响应式执行时,必须显式复制并在完成后清理 traceId;不得假设 MDC 自动跨线程传播。
  • 如果后续接入 OpenTelemetry,优先兼容 W3C traceparent,并由观测层映射业务使用的 traceId;不要同时维护两套互不关联的链路标识。

测试与验收

  • 合法 X-Trace-Id:响应头、MDC 日志、错误体和审计记录使用原值。
  • 缺失或非法 X-Trace-Id:后端生成符合规则的新值,响应头和错误体一致。
  • 正常响应、参数校验失败、业务冲突和未处理异常均可通过响应中的 traceId 定位对应日志。
  • 同一请求结束后 MDC 被清理;连续处理两个不同请求不会串号。
  • 下游 HTTP 调用收到当前请求的 X-Trace-Id
  • 前端不再在各业务方法重复生成或设置 traceId;统一请求客户端覆盖 GET、POST、PUT、PATCH、DELETE。

禁止做法

  • 不把 traceId 放入 query、path 或业务请求体,不允许客户端通过 traceId 获得额外权限。
  • 不在 Controller、Service、Repository 各生成一次 traceId,不在异常处理器覆盖已有值。
  • 不使用不可清理的静态变量保存当前 traceId,不把 MDC 当成业务数据源。
  • 不因 traceId 缺失返回伪造成功,也不吞掉原始业务异常。