全局中间件 #

一、全局中间件概述 #

1.1 什么是全局中间件 #

全局中间件应用于所有路由请求,在请求到达任何处理函数之前都会执行:

go
func main() {
    r := gin.New()
    
    // 全局中间件 - 应用于所有路由
    r.Use(gin.Logger())
    r.Use(gin.Recovery())
    
    r.Run()
}

1.2 全局中间件特点 #

特点 说明
全局生效 应用于所有路由
优先执行 在路由中间件之前执行
统一处理 适合日志、恢复等通用功能

二、内置全局中间件 #

2.1 Logger中间件 #

go
func main() {
    r := gin.New()
    
    // Logger中间件记录请求日志
    r.Use(gin.Logger())
    
    r.GET("/", func(c *gin.Context) {
        c.String(200, "Hello")
    })
    
    r.Run()
}

// 日志输出示例:
// [GIN] 2024/01/01 - 10:00:00 | 200 |      12.345µs | 127.0.0.1 | GET      "/"

2.2 自定义Logger格式 #

go
func main() {
    r := gin.New()
    
    // 自定义Logger格式
    r.Use(gin.LoggerWithFormatter(func(param gin.LogFormatterParams) string {
        return fmt.Sprintf("[GIN] %s | %s | %d | %v | %s | %s %s\n",
            param.TimeStamp.Format("2006/01/02 - 15:04:05"),
            param.ClientIP,
            param.StatusCode,
            param.Latency,
            param.Method,
            param.Path,
            param.ErrorMessage,
        )
    }))
    
    r.Run()
}

2.3 LoggerWithWriter #

go
func main() {
    r := gin.New()
    
    // 将日志写入文件
    file, _ := os.Create("gin.log")
    r.Use(gin.LoggerWithWriter(file))
    
    r.Run()
}

2.4 Recovery中间件 #

go
func main() {
    r := gin.New()
    
    // Recovery中间件捕获panic
    r.Use(gin.Recovery())
    
    r.GET("/panic", func(c *gin.Context) {
        panic("Something went wrong!")
    })
    
    r.Run()
}

// panic被捕获,返回500错误,服务不会崩溃

2.5 自定义Recovery #

go
func main() {
    r := gin.New()
    
    // 自定义Recovery处理
    r.Use(gin.CustomRecovery(func(c *gin.Context, recovered interface{}) {
        if err, ok := recovered.(string); ok {
            c.JSON(500, gin.H{
                "code":    500,
                "message": "服务器内部错误",
                "error":   err,
            })
        }
        c.AbortWithStatus(500)
    }))
    
    r.GET("/panic", func(c *gin.Context) {
        panic("Something went wrong!")
    })
    
    r.Run()
}

2.6 Default方法 #

go
func main() {
    // gin.Default() 默认包含Logger和Recovery
    r := gin.Default()
    
    // 等价于
    r := gin.New()
    r.Use(gin.Logger())
    r.Use(gin.Recovery())
    
    r.Run()
}

三、自定义全局中间件 #

3.1 基本结构 #

go
func MyMiddleware() gin.HandlerFunc {
    return func(c *gin.Context) {
        // 前置处理
        
        c.Next()
        
        // 后置处理
    }
}

func main() {
    r := gin.New()
    r.Use(MyMiddleware())
    r.Run()
}

3.2 请求日志中间件 #

go
func RequestLogger() gin.HandlerFunc {
    return func(c *gin.Context) {
        start := time.Now()
        
        // 请求信息
        log.Printf("[REQUEST] %s %s %s",
            c.Request.Method,
            c.Request.URL.Path,
            c.ClientIP(),
        )
        
        c.Next()
        
        // 响应信息
        log.Printf("[RESPONSE] %s %s %d %v",
            c.Request.Method,
            c.Request.URL.Path,
            c.Writer.Status(),
            time.Since(start),
        )
    }
}

func main() {
    r := gin.New()
    r.Use(RequestLogger())
    r.Run()
}

3.3 请求ID中间件 #

go
func RequestID() gin.HandlerFunc {
    return func(c *gin.Context) {
        // 从请求头获取或生成请求ID
        requestID := c.GetHeader("X-Request-ID")
        if requestID == "" {
            requestID = uuid.New().String()
        }
        
        // 设置到上下文和响应头
        c.Set("requestId", requestID)
        c.Header("X-Request-ID", requestID)
        
        c.Next()
    }
}

func main() {
    r := gin.New()
    r.Use(RequestID())
    r.Run()
}

3.4 CORS中间件 #

go
func CORS() gin.HandlerFunc {
    return func(c *gin.Context) {
        c.Header("Access-Control-Allow-Origin", "*")
        c.Header("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS")
        c.Header("Access-Control-Allow-Headers", "Content-Type, Authorization")
        c.Header("Access-Control-Expose-Headers", "Content-Length")
        c.Header("Access-Control-Max-Age", "86400")
        
        if c.Request.Method == "OPTIONS" {
            c.AbortWithStatus(204)
            return
        }
        
        c.Next()
    }
}

func main() {
    r := gin.New()
    r.Use(CORS())
    r.Run()
}

3.5 安全头中间件 #

go
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.Header("Content-Security-Policy", "default-src 'self'")
        
        c.Next()
    }
}

func main() {
    r := gin.New()
    r.Use(SecurityHeaders())
    r.Run()
}

3.6 性能监控中间件 #

go
func PerformanceMonitor() gin.HandlerFunc {
    return func(c *gin.Context) {
        start := time.Now()
        
        c.Next()
        
        latency := time.Since(start)
        
        // 慢请求告警
        if latency > time.Second {
            log.Printf("[SLOW] %s %s took %v",
                c.Request.Method,
                c.Request.URL.Path,
                latency,
            )
        }
        
        // 记录性能指标
        metrics.RecordLatency(latency)
        metrics.RecordStatus(c.Writer.Status())
    }
}

func main() {
    r := gin.New()
    r.Use(PerformanceMonitor())
    r.Run()
}

3.7 限流中间件 #

go
func RateLimit(rps int) gin.HandlerFunc {
    limiter := rate.NewLimiter(rate.Limit(rps), rps*2)
    
    return func(c *gin.Context) {
        if !limiter.Allow() {
            c.AbortWithStatusJSON(429, gin.H{
                "code":    429,
                "message": "请求过于频繁",
            })
            return
        }
        c.Next()
    }
}

func main() {
    r := gin.New()
    r.Use(RateLimit(100)) // 每秒100个请求
    r.Run()
}

四、中间件配置 #

4.1 配置化中间件 #

go
type MiddlewareConfig struct {
    EnableLogger    bool
    EnableRecovery  bool
    EnableCORS      bool
    EnableRateLimit bool
    RateLimitRPS    int
    CORSOrigins     []string
}

func SetupMiddleware(r *gin.Engine, config *MiddlewareConfig) {
    if config.EnableLogger {
        r.Use(gin.Logger())
    }
    
    if config.EnableRecovery {
        r.Use(gin.Recovery())
    }
    
    if config.EnableCORS {
        r.Use(CORSWithConfig(config.CORSOrigins))
    }
    
    if config.EnableRateLimit {
        r.Use(RateLimit(config.RateLimitRPS))
    }
}

func main() {
    config := &MiddlewareConfig{
        EnableLogger:    true,
        EnableRecovery:  true,
        EnableCORS:      true,
        EnableRateLimit: true,
        RateLimitRPS:    100,
        CORSOrigins:     []string{"*"},
    }
    
    r := gin.New()
    SetupMiddleware(r, config)
    r.Run()
}

4.2 环境区分 #

go
func main() {
    r := gin.New()
    
    // 根据环境配置中间件
    switch gin.Mode() {
    case gin.DebugMode:
        r.Use(gin.Logger())
        r.Use(DebugMiddleware())
        
    case gin.ReleaseMode:
        r.Use(gin.Recovery())
        r.Use(ProductionMiddleware())
        r.Use(RateLimit(100))
        
    case gin.TestMode:
        r.Use(TestMiddleware())
    }
    
    r.Run()
}

五、中间件链 #

5.1 链式注册 #

go
func main() {
    r := gin.New()
    
    // 链式注册多个中间件
    r.Use(
        RequestID(),
        RequestLogger(),
        gin.Recovery(),
        CORS(),
        SecurityHeaders(),
    )
    
    r.Run()
}

5.2 中间件顺序 #

go
func main() {
    r := gin.New()
    
    // 推荐的中间件顺序
    r.Use(
        // 1. 请求ID(最先执行,方便追踪)
        RequestID(),
        
        // 2. 日志记录
        RequestLogger(),
        
        // 3. 错误恢复(捕获后续panic)
        gin.Recovery(),
        
        // 4. 安全相关
        SecurityHeaders(),
        CORS(),
        
        // 5. 限流(保护服务器)
        RateLimit(100),
    )
    
    r.Run()
}

六、全局中间件最佳实践 #

6.1 错误处理 #

go
func RecoveryMiddleware() gin.HandlerFunc {
    return func(c *gin.Context) {
        defer func() {
            if err := recover(); err != nil {
                // 记录错误
                log.Printf("[PANIC] %v\n%s", err, debug.Stack())
                
                // 返回错误响应
                c.AbortWithStatusJSON(500, gin.H{
                    "code":    500,
                    "message": "服务器内部错误",
                })
            }
        }()
        
        c.Next()
    }
}

6.2 优雅关闭 #

go
func main() {
    r := gin.New()
    r.Use(gin.Logger())
    r.Use(gin.Recovery())
    
    srv := &http.Server{
        Addr:    ":8080",
        Handler: r,
    }
    
    go func() {
        if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
            log.Fatalf("listen: %s\n", err)
        }
    }()
    
    // 等待中断信号
    quit := make(chan os.Signal, 1)
    signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
    <-quit
    
    // 优雅关闭
    ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
    defer cancel()
    
    if err := srv.Shutdown(ctx); err != nil {
        log.Fatal("Server forced to shutdown:", err)
    }
    
    log.Println("Server exiting")
}

6.3 健康检查 #

go
func main() {
    r := gin.New()
    r.Use(gin.Recovery())
    
    // 健康检查不需要日志
    r.GET("/health", func(c *gin.Context) {
        c.JSON(200, gin.H{"status": "ok"})
    })
    
    // 其他路由使用日志
    api := r.Group("/api")
    api.Use(gin.Logger())
    {
        api.GET("/users", listUsers)
    }
    
    r.Run()
}

七、总结 #

7.1 核心要点 #

要点 说明
注册方式 r.Use(middleware)
内置中间件 Logger、Recovery
执行顺序 注册顺序即执行顺序
应用场景 日志、恢复、安全、限流

7.2 最佳实践 #

实践 说明
合理顺序 请求ID → 日志 → 恢复 → 安全 → 限流
配置化 通过配置控制中间件开关
环境区分 不同环境使用不同中间件
健康检查 排除不必要的中间件

7.3 下一步 #

现在你已经掌握了全局中间件,接下来让我们学习 路由级中间件,深入了解路由级别的中间件应用!

最后更新:2026-03-28