mirror of
https://github.com/2930134478/AI-CS.git
synced 2026-06-15 00:44:30 +08:00
126 lines
3.0 KiB
Go
126 lines
3.0 KiB
Go
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()
|
|
}
|
|
}
|