全部学科
Python全栈
python
NodeJS全栈
nodejs
小程序首页
📅 2026-05-18 7 分钟 ✍️ juanwangdev

自定义中间件编写

中间件是 Gin 请求处理链的核心组件,自定义中间件可灵活扩展功能。

中间件基本结构

Go
// 中间件签名
type HandlerFunc func(c *gin.Context)

// 基本格式
func myMiddleware() gin.HandlerFunc {
    return func(c *gin.Context) {
        // 前置处理
        c.Next() // 调用后续处理
        // 后置处理
    }
}

认证中间件

Go
func authMiddleware() gin.HandlerFunc {
    return func(c *gin.Context) {
        token := c.GetHeader("Authorization")
        if token == "" {
            c.AbortWithStatusJSON(401, gin.H{
                "code":    401,
                "message": "未提供认证信息",
            })
            return
        }

        // 验证 token
        claims, err := validateToken(token)
        if err != nil {
            c.AbortWithStatusJSON(401, gin.H{
                "code":    401,
                "message": "token 无效",
            })
            return
        }

        // 存储用户信息
        c.Set("user_id", claims.UserID)
        c.Set("role", claims.Role)
        c.Next()
    }
}

日志中间件

Go
func loggerMiddleware() gin.HandlerFunc {
    return func(c *gin.Context) {
        start := time.Now()
        path := c.Request.URL.Path
        method := c.Request.Method

        c.Next()

        duration := time.Since(start)
        status := c.Writer.Status()

        log.Printf("[%s] %s %s %d %v",
            method, path, c.ClientIP(), status, duration)
    }
}

CORS 中间件

Go
func corsMiddleware() 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")

        if c.Request.Method == "OPTIONS" {
            c.AbortWithStatus(204)
            return
        }

        c.Next()
    }
}

请求限流中间件

Go
func rateLimitMiddleware(limit int) gin.HandlerFunc {
    limiter := make(map[string]int)
    mutex := sync.Mutex{}

    return func(c *gin.Context) {
        ip := c.ClientIP()

        mutex.Lock()
        count := limiter[ip]
        if count >= limit {
            mutex.Unlock()
            c.AbortWithStatusJSON(429, gin.H{
                "code":    429,
                "message": "请求过于频繁",
            })
            return
        }
        limiter[ip] = count + 1
        mutex.Unlock()

        c.Next()
    }
}

请求超时中间件

Go
func timeoutMiddleware(timeout time.Duration) gin.HandlerFunc {
    return func(c *gin.Context) {
        ctx, cancel := context.WithTimeout(c.Request.Context(), timeout)
        defer cancel()

        c.Request = c.Request.WithContext(ctx)

        done := make(chan struct{})
        go func() {
            c.Next()
            close(done)
        }()

        select {
        case <-done:
            // 正常完成
        case <-ctx.Done():
            c.AbortWithStatusJSON(504, gin.H{
                "code":    504,
                "message": "请求超时",
            })
        }
    }
}

中间件注册方式

Go
func main() {
    r := gin.New()

    // 全局注册
    r.Use(loggerMiddleware())
    r.Use(corsMiddleware())

    // 路由组注册
    api := r.Group("/api")
    api.Use(authMiddleware())

    // 单路由注册
    r.GET("/admin", authMiddleware(), adminHandler)

    r.Run(":8080")
}

带参数中间件

Go
func rateLimit(limit int, window time.Duration) gin.HandlerFunc {
    return func(c *gin.Context) {
        // 使用 limit 和 window 参数
        c.Next()
    }
}

// 注册时传入参数
r.Use(rateLimit(100, time.Minute))

中间件获取用户信息

Go
func roleMiddleware(requiredRole string) gin.HandlerFunc {
    return func(c *gin.Context) {
        role, exists := c.Get("role")
        if !exists {
            c.AbortWithStatus(401)
            return
        }

        if role != requiredRole {
            c.AbortWithStatusJSON(403, gin.H{
                "message": "权限不足",
            })
            return
        }

        c.Next()
    }
}

// 需先经过 authMiddleware 设置 role
adminGroup := r.Group("/admin")
adminGroup.Use(authMiddleware())
adminGroup.Use(roleMiddleware("admin"))

中间件注册顺序影响执行顺序,认证类放前,日志类放最前或最后。

要点总结

  • 中间件返回 gin.HandlerFunc 函数
  • c.Next() 调用后续处理,c.Abort() 终止
  • c.Set() 存储数据,c.Get() 获取数据
  • 全局注册用 r.Use(),路由组用 group.Use()
  • 可通过闭包传递参数给中间件

📝 发现内容有误?点击此处直接编辑

← 上一篇 第三方中间件集成
下一篇 → Gin 日志分级与格式化
想查看更多题目和详细解析?
小程序提供完整的题库、模拟考试和详细解析
马上就来

长按或扫描二维码,立即体验

扫码体验小程序
马上就来
使用微信扫描二维码
立即体验完整题库