Files
group_fqcd_jr/app/api/middleware.py
T
张胜宇 e239eb778b docs: 品牌全量口径统一为「南方基金」+ 作废文档清理
1) 客服 Agent 四份交付文档 + 构建脚手架:品牌由包装占位 XX科技 / 旧名 南方财富
   统一为南方基金(热线 400-889-8899 / 官网 nffund.com),系统名改为「智能服务系统」;
   同步追加 §0.4 修订记录行,工程记录行保留原占位字面以支撑硬编码扫描验收。
2) 开发文档:清理 28 份已作废/残留文档(14 份移出归档 + 14 份仓库副本),
   新增《文档规整方案与开发前待决事项-2026-09-17》。
3) 客服agent 四份交付文档首次纳入本分支。
2026-09-17 15:15:22 +08:00

33 lines
1.4 KiB
Python

"""HTTP 层横切关注点。
目前只有一项:统一回传 `X-Trace-ID`。接口文档把它列为所有响应的必备头,
但此前**完全没有实现**——客户端拿到错误也无法把请求与服务端日志对上。
放在独立模块而不是写在 `create_app()` 里,是为了让它可被单独测试:
中间件函数不需要起整个应用就能验证三条分支(有请求上下文 / 只有请求头 / 两者都没有)。
"""
from collections.abc import Awaitable, Callable
from starlette.requests import Request
from starlette.responses import Response
TRACE_ID_HEADER = "X-Trace-ID"
RequestHandler = Callable[[Request], Awaitable[Response]]
async def attach_trace_id(request: Request, call_next: RequestHandler) -> Response:
"""给响应附加 `X-Trace-ID`。
优先级:请求上下文里的 `trace_id`(服务端生成或从令牌解析)→ 请求头里客户端带来的
`X-Trace-ID`(透传,便于把客户端日志与服务端串起来)。两者都没有就不加头:
认证失败等场景还没建立上下文,此时凭空造一个 id 只会误导排障。
"""
response = await call_next(request)
context = getattr(request.state, "request_context", None)
trace_id = getattr(context, "trace_id", None) or request.headers.get(TRACE_ID_HEADER)
if trace_id:
response.headers[TRACE_ID_HEADER] = str(trace_id)
return response