全局中间件会对所有请求生效,适合处理通用逻辑,比如日志、错误恢复、跨域等。
使用 r.Use() 注册全局中间件:
package main
import (
"log"
"time"
"github.com/gin-gonic/gin"
)
func main() {
r := gin.New()
r.Use(gin.Logger())
r.Use(gin.Recovery())
r.Use(func(c *gin.Context) {
start := time.Now()
c.Next()
log.Printf("请求耗时: %v", time.Since(start))
})
r.GET("/api", func(c *gin.Context) {
c.JSON(200, gin.H{"message": "Hello"})
})
r.Run(":8080")
}
为每个请求生成唯一 ID,方便追踪:
import "github.com/google/uuid"
func RequestID() gin.HandlerFunc {
return func(c *gin.Context) {
requestID := c.GetHeader("X-Request-ID")
if requestID == "" {
requestID = uuid.New().String()
}
c.Set("RequestID", requestID)
c.Header("X-Request-ID", requestID)
c.Next()
}
}
r.Use(RequestID())
记录每个请求的处理时间:
func Timing() gin.HandlerFunc {
return func(c *gin.Context) {
start := time.Now()
c.Next()
duration := time.Since(start)
c.Header("X-Response-Time", duration.String())
log.Printf("[%s] %s %s - %d - %v",
c.Request.Method,
c.Request.URL.Path,
c.ClientIP(),
c.Writer.Status(),
duration,
)
}
}
r.Use(Timing())
添加常用的安全响应头:
func SecurityHeaders() gin.HandlerFunc {
return func(c *gin.Context) {
c.Header("X-Content-Type-Options", "nosniff")
c.Header("X-Frame-Options", "DENY")
c.Header("X-XSS-Protection", "1; mode=block")
c.Header("Strict-Transport-Security", "max-age=31536000; includeSubDomains")
c.Next()
}
}
r.Use(SecurityHeaders())
防止大请求攻击:
func MaxBodySize(max int64) gin.HandlerFunc {
return func(c *gin.Context) {
if c.Request.ContentLength > max {
c.AbortWithStatusJSON(413, gin.H{
"error": "请求体过大",
})
return
}
c.Request.Body = http.MaxBytesReader(c.Writer, c.Request.Body, max)
c.Next()
}
}
r.Use(MaxBodySize(10 * 1024 * 1024))
更完整的日志记录:
func DetailedLogger() gin.HandlerFunc {
return func(c *gin.Context) {
start := time.Now()
path := c.Request.URL.Path
query := c.Request.URL.RawQuery
c.Next()
latency := time.Since(start)
status := c.Writer.Status()
clientIP := c.ClientIP()
method := c.Request.Method
log.Printf("[GIN] %v | %3d | %13v | %15s | %-7s %s",
start.Format("2006/01/02 - 15:04:05"),
status,
latency,
clientIP,
method,
path+"?"+query,
)
}
}
r.Use(DetailedLogger())
某些中间件可能只在特定条件下生效:
func ConditionalMiddleware(condition func(*gin.Context) bool, middleware gin.HandlerFunc) gin.HandlerFunc {
return func(c *gin.Context) {
if condition(c) {
middleware(c)
} else {
c.Next()
}
}
}
r.Use(ConditionalMiddleware(
func(c *gin.Context) bool {
return !strings.HasPrefix(c.Request.URL.Path, "/health")
},
DetailedLogger(),
))
全局中间件的注册顺序决定了执行顺序:
r.Use(Middleware1())
r.Use(Middleware2())
r.Use(Middleware3())
执行顺序:1前 → 2前 → 3前 → 处理器 → 3后 → 2后 → 1后
一般建议顺序:
全局中间件适合处理所有请求共有的逻辑。注册时要注意顺序,先注册的中间件先执行"前"逻辑,后执行"后"逻辑。合理使用全局中间件可以让代码更加整洁,避免在每个处理器中重复相同的逻辑。