Gin框架中间件详解

Gin框架中间件详解

1. 中间件绑定路由的几种方式

1.1 全局中间件

package main

import "github.com/gin-gonic/gin"

func GlobalMiddleware() gin.HandlerFunc {
    return func(c *gin.Context) {
        // 中间件逻辑
        c.Next()
    }
}

func main() {
    r := gin.Default()
  
    // 注册全局中间件(对所有路由生效)
    r.Use(GlobalMiddleware())
  
    r.GET("/hello", func(c *gin.Context) {
        c.String(200, "Hello World")
    })
  
    r.Run(":8080")
}

1.2 路由组中间件

func main() {
    r := gin.Default()
  
    // 为路由组注册中间件
    api := r.Group("/api", ApiMiddleware())
    // 或者使用Use方法
    // api := r.Group("/api")
    // api.Use(ApiMiddleware())
  
    api.GET("/users", func(c *gin.Context) {
        c.String(200, "用户列表")
    })
  
    api.GET("/products", func(c *gin.Context) {
        c.String(200, "产品列表")
    })
}

func ApiMiddleware() gin.HandlerFunc {
    return func(c *gin.Context) {
        // API特定中间件逻辑
        c.Next()
    }
}

1.3 单个路由中间件

func main() {
    r := gin.Default()
  
    // 为单个路由注册中间件
    r.GET("/admin", AuthMiddleware(), func(c *gin.Context) {
        c.String(200, "管理员页面")
    })
  
    // 多个中间件
    r.POST("/upload", LogMiddleware(), AuthMiddleware(), UploadHandler)
}

func AuthMiddleware() gin.HandlerFunc {
    return func(c *gin.Context) {
        // 认证逻辑
        c.Next()
    }
}

func LogMiddleware() gin.HandlerFunc {
    return func(c *gin.Context) {
        // 日志记录逻辑
        c.Next()
    }
}

1.4 链式调用多个中间件

func main() {
    r := gin.Default()
  
    // 链式注册多个中间件
    adminGroup := r.Group("/admin")
    adminGroup.Use(LogMiddleware(), AuthMiddleware(), AdminCheckMiddleware())
  
    adminGroup.GET("/dashboard", func(c *gin.Context) {
        c.String(200, "管理面板")
    })
}

2. Next() 和 Abort() 函数

2.1 Next() 函数

func LoggerMiddleware() gin.HandlerFunc {
    return func(c *gin.Context) {
        // 请求处理前
        start := time.Now()
      
        // 执行后续的中间件和处理函数
        c.Next()
      
        // 请求处理后
        latency := time.Since(start)
        fmt.Printf("请求 %s 耗时 %v\n", c.Request.URL.Path, latency)
    }
}

func AuthMiddleware() gin.HandlerFunc {
    return func(c *gin.Context) {
        token := c.GetHeader("Authorization")
        if token == "" {
            c.JSON(401, gin.H{"error": "未授权"})
            c.Abort() // 终止后续处理
            return
        }
      
        // 验证token...
        c.Next() // 继续执行后续中间件
    }
}

2.2 Abort() 函数

func RateLimitMiddleware() gin.HandlerFunc {
    return func(c *gin.Context) {
        if isRateLimited(c.ClientIP()) {
            c.JSON(429, gin.H{"error": "请求过于频繁"})
            c.Abort() // 立即终止,不会执行后续中间件
            return
        }
        c.Next()
    }
}

// AbortWithStatus() - 终止并设置状态码
func MaintenanceMiddleware() gin.HandlerFunc {
    return func(c *gin.Context) {
        if isMaintenanceMode {
            c.AbortWithStatusJSON(503, gin.H{"message": "系统维护中"})
            return
        }
        c.Next()
    }
}

// AbortWithError() - 终止并返回错误
func ErrorHandlerMiddleware() gin.HandlerFunc {
    return func(c *gin.Context) {
        defer func() {
            if err := recover(); err != nil {
                c.AbortWithError(500, fmt.Errorf("内部错误: %v", err))
            }
        }()
        c.Next()
    }
}

3. 中间件的 Set 和 Get 操作

3.1 设置和获取值

func UserMiddleware() gin.HandlerFunc {
    return func(c *gin.Context) {
        // 设置值到上下文
        user := getUserFromToken(c)
        c.Set("user", user)
        c.Set("request_id", generateRequestID())
      
        c.Next()
    }
}

func UserProfileHandler(c *gin.Context) {
    // 从上下文获取值
    if user, exists := c.Get("user"); exists {
        if userInfo, ok := user.(*User); ok {
            c.JSON(200, gin.H{"user": userInfo})
            return
        }
    }
  
    // 获取值并检查类型
    if requestID, exists := c.Get("request_id"); exists {
        fmt.Printf("Request ID: %s\n", requestID)
    }
  
    c.JSON(400, gin.H{"error": "用户信息不存在"})
}

3.2 完整的示例

package main

import (
    "fmt"
    "github.com/gin-gonic/gin"
    "time"
)

type User struct {
    ID   int    `json:"id"`
    Name string `json:"name"`
}

func main() {
    r := gin.Default()
  
    // 全局中间件
    r.Use(LoggerMiddleware())
    r.Use(AuthMiddleware())
  
    // 路由组中间件
    api := r.Group("/api")
    api.Use(SetRequestInfoMiddleware())
  
    api.GET("/user", GetUserHandler)
    api.POST("/upload", UploadHandler)
  
    r.Run(":8080")
}

func LoggerMiddleware() gin.HandlerFunc {
    return func(c *gin.Context) {
        start := time.Now()
        c.Next()
        latency := time.Since(start)
        fmt.Printf("[%s] %s %s - %v\n", 
            time.Now().Format("2006-01-02 15:04:05"),
            c.Request.Method,
            c.Request.URL.Path,
            latency,
        )
    }
}

func AuthMiddleware() gin.HandlerFunc {
    return func(c *gin.Context) {
        token := c.GetHeader("Authorization")
        if token == "" {
            c.AbortWithStatusJSON(401, gin.H{"error": "需要认证"})
            return
        }
      
        // 模拟用户验证
        user := &User{ID: 1, Name: "张三"}
        c.Set("user", user)
        c.Next()
    }
}

func SetRequestInfoMiddleware() gin.HandlerFunc {
    return func(c *gin.Context) {
        c.Set("request_time", time.Now())
        c.Set("client_ip", c.ClientIP())
        c.Next()
    }
}

func GetUserHandler(c *gin.Context) {
    user, _ := c.Get("user")
    requestTime, _ := c.Get("request_time")
    clientIP, _ := c.Get("client_ip")
  
    c.JSON(200, gin.H{
        "user":         user,
        "request_time": requestTime,
        "client_ip":    clientIP,
    })
}

func UploadHandler(c *gin.Context) {
    // 检查用户权限
    if user, exists := c.Get("user"); exists {
        if u, ok := user.(*User); ok {
            if u.ID != 1 { // 简单的权限检查
                c.AbortWithStatusJSON(403, gin.H{"error": "权限不足"})
                return
            }
        }
    }
  
    // 处理上传逻辑
    c.JSON(200, gin.H{"message": "上传成功"})
}

3.3 中间件执行顺序的重要性

func main() {
    r := gin.Default()
  
    // 中间件执行顺序:Logger → Auth → SetInfo
    r.Use(LoggerMiddleware())      // 最先执行
    r.Use(AuthMiddleware())        // 其次执行
    r.Use(SetRequestInfoMiddleware()) // 最后执行
  
    r.GET("/test", func(c *gin.Context) {
        // 在这里可以访问所有中间件设置的值
        c.JSON(200, gin.H{
            "message": "测试路由",
        })
    })
}

关键点总结

  1. 绑定方式:全局中间件、路由组中间件、单个路由中间件
  2. Next():继续执行后续中间件和处理函数
  3. Abort():终止当前请求的后续处理
  4. Set/Get:在中间件间传递数据,使用类型断言确保类型安全
  5. 执行顺序:中间件按照注册顺序执行,Next()前后的代码分别在请求前后执行

这些功能使得Gin中间件非常灵活,可以用于认证、日志、限流、数据预处理等多种场景。

posted @ 2026-01-07 09:08  shuix1ng  阅读(12)  评论(0)    收藏  举报