| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125 |
- package middleware
- import (
- "crypto/rand"
- "encoding/hex"
- "log"
- "net/http"
- "strconv"
- "time"
- "github.com/2930134478/AI-CS/backend/service"
- "github.com/gin-contrib/cors"
- "github.com/gin-gonic/gin"
- )
- func newTraceID() string {
- var b [8]byte
- if _, err := rand.Read(b[:]); err != nil {
- return strconv.FormatInt(time.Now().UnixNano(), 10)
- }
- return hex.EncodeToString(b[:])
- }
- // TraceID 为每个请求注入 trace_id,便于链路排障。
- func TraceID() gin.HandlerFunc {
- return func(c *gin.Context) {
- traceID := c.GetHeader("X-Trace-Id")
- if traceID == "" {
- traceID = newTraceID()
- }
- c.Set("trace_id", traceID)
- c.Writer.Header().Set("X-Trace-Id", traceID)
- c.Next()
- }
- }
- func Logger() gin.HandlerFunc {
- return func(c *gin.Context) {
- start := time.Now()
- //继续调用后续的中间件处理函数
- c.Next()
- log.Printf("[GIN] %s %s %d %s",
- c.Request.Method, c.Request.URL.Path, c.Writer.Status(), time.Since(start))
- }
- }
- // StructuredHTTPLogger 将 HTTP 请求结构化落库(分类: http)。
- func StructuredHTTPLogger(logSvc *service.SystemLogService) gin.HandlerFunc {
- return func(c *gin.Context) {
- start := time.Now()
- c.Next()
- if logSvc == nil {
- return
- }
- latencyMs := time.Since(start).Milliseconds()
- status := c.Writer.Status()
- level := "info"
- if status >= 500 {
- level = "error"
- } else if status >= 400 || latencyMs >= 2000 {
- level = "warn"
- }
- var userID *uint
- if v := c.GetHeader("X-User-Id"); v != "" {
- if id, err := strconv.ParseUint(v, 10, 64); err == nil && id > 0 {
- t := uint(id)
- userID = &t
- }
- }
- traceID := ""
- if v, ok := c.Get("trace_id"); ok {
- if s, ok2 := v.(string); ok2 {
- traceID = s
- }
- }
- _ = logSvc.Create(service.CreateSystemLogInput{
- Level: level,
- Category: "http",
- Event: "http_request",
- Source: "backend",
- TraceID: traceID,
- UserID: userID,
- Message: c.Request.Method + " " + c.Request.URL.Path,
- Meta: map[string]interface{}{
- "status": status,
- "latency_ms": latencyMs,
- "path": c.Request.URL.Path,
- "method": c.Request.Method,
- "query": c.Request.URL.RawQuery,
- },
- })
- }
- }
- func CORS() gin.HandlerFunc {
- return cors.New(cors.Config{
- AllowOrigins: []string{"*"},
- AllowMethods: []string{"GET", "POST", "PUT", "DELETE", "OPTIONS"},
- AllowHeaders: []string{"Origin", "Content-Type", "Accept", "X-User-Id", "X-Trace-Id"},
- AllowCredentials: false,
- })
- }
- // RequireAuth 认证中间件:要求请求头中包含有效的 X-User-Id
- func RequireAuth() gin.HandlerFunc {
- return func(c *gin.Context) {
- userIDStr := c.GetHeader("X-User-Id")
- if userIDStr == "" {
- c.JSON(http.StatusUnauthorized, gin.H{"error": "未授权访问,请提供 X-User-Id 请求头"})
- c.Abort()
- return
- }
- userID, err := strconv.ParseUint(userIDStr, 10, 64)
- if err != nil || userID == 0 {
- c.JSON(http.StatusUnauthorized, gin.H{"error": "用户ID不合法"})
- c.Abort()
- return
- }
- // 将用户ID存储到上下文中,供后续使用
- c.Set("user_id", uint(userID))
- c.Next()
- }
- }
|