package middleware import ( "crypto/rand" "encoding/hex" "fmt" "time" "github.com/gin-gonic/gin" ) const ( // TraceIDHeader 追踪 ID 的 HTTP 响应头名称 TraceIDHeader = "X-Trace-ID" // TraceIDKey gin.Context 中的 key TraceIDKey = "trace_id" ) // TraceID 中间件:为每个请求生成唯一追踪 ID // 追踪 ID 写入 gin.Context 和响应头,供日志和下游服务关联 func TraceID() gin.HandlerFunc { return func(c *gin.Context) { // 优先复用上游传入的 Trace ID(如 API 网关、前端) traceID := c.GetHeader(TraceIDHeader) if traceID == "" { traceID = generateTraceID() } c.Set(TraceIDKey, traceID) c.Header(TraceIDHeader, traceID) c.Next() } } // generateTraceID 生成 16 字节随机 hex 字符串,格式:时间前缀+随机后缀 // 例:20260405-a1b2c3d4e5f60718 func generateTraceID() string { b := make([]byte, 8) _, err := rand.Read(b) if err != nil { // 降级:使用时间戳 return fmt.Sprintf("%d", time.Now().UnixNano()) } return fmt.Sprintf("%s-%s", time.Now().Format("20060102"), hex.EncodeToString(b)) } // GetTraceID 从 gin.Context 获取 trace ID(供 handler 使用) func GetTraceID(c *gin.Context) string { if v, exists := c.Get(TraceIDKey); exists { if id, ok := v.(string); ok { return id } } return "" }