// services/api/src/request-id.middleware.ts // 请求 ID 约定:优先透传上游 x-request-id(网关/前端可携带),否则生成 UUID v4; // 挂到 req.id(pino-http 日志字段)并写回响应头 x-request-id,便于全链路排障。 // 长度上限(Task 7 遗留项④):上游值 >128 字符时视为滥用/异常,静默换成新 UUID //(不透传也不告警——日志与响应头由本函数统一写回,不会出现半截 ID)。 // genReqId 与本中间件共用 resolveRequestId,先后顺序不影响结果。 import { randomUUID } from 'node:crypto'; import type { ServerResponse } from 'node:http'; import type { NestMiddleware } from '@nestjs/common'; import type { ServerRequestWithId } from './shared/request-with-id'; /** 透传上游 x-request-id 的长度上限(UUID v4 为 36 字符,128 已十分宽裕)。 */ export const MAX_REQUEST_ID_LENGTH = 128; export function resolveRequestId( req: ServerRequestWithId, res: ServerResponse, ): string { if (req.id) { return req.id; } const header = req.headers['x-request-id']; const fromHeader = Array.isArray(header) ? header[0] : header; const id = typeof fromHeader === 'string' && fromHeader.trim() !== '' && fromHeader.length <= MAX_REQUEST_ID_LENGTH ? fromHeader : randomUUID(); req.id = id; res.setHeader('x-request-id', id); return id; } export class RequestIdMiddleware implements NestMiddleware { use(req: ServerRequestWithId, res: ServerResponse, next: () => void): void { resolveRequestId(req, res); next(); } }