Gin框架中间件使用

发布于:2025-08-16 ⋅ 阅读:(16) ⋅ 点赞:(0)

Gin框架中间件的作用

1.主要作用

  • 请求预处理:在请求到达路由处理函数之前执行
  • 响应后处理:在路由处理函数执行后对响应进行处理
  • 权限验证:如身份认证、角色检查等
  • 日志记录:记录请求和响应信息
  • 跨域处理:设置 CORS 头部
  • 限流控制:限制请求频率
  • 错误处理:统一处理错误和异常
  • 数据压缩:对响应数据进行压缩

2.执行顺序

请求 → 中间件1 → 中间件2 → 路由处理函数 → 中间件2 → 中间件1 → 响应

3.自定义中间件设计

func MiddlewareName() gin.HandlerFunc {
    return func(c *gin.Context) {
        // 请求前处理
        
        c.Next() // 调用后续处理函数
        
        // 响应后处理
    }
}

4.实际案例

下面是一个完整的中间件示例,包含多个常用的中间件

// middleware/middleware.go
package middleware

import (
	"fmt"
	"log"
	"net/http"
	"strings"
	"time"

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

// LoggerMiddleware 日志中间件 - 记录请求信息
func LoggerMiddleware() gin.HandlerFunc {
	return func(c *gin.Context) {
		// 开始时间
		start := time.Now()
		
		// 处理请求
		c.Next()
		
		// 结束时间
		end := time.Now()
		latency := end.Sub(start)
		
		// 获取状态码
		statusCode := c.Writer.Status()
		
		// 记录日志
		log.Printf("[GIN] %v | %3d | %13v | %15s | %-7s %#v",
			end.Format("2006/01/02 - 15:04:05"),
			statusCode,
			latency,
			c.ClientIP(),
			c.Request.Method,
			c.Request.URL.Path,
		)
	}
}

// CORSMiddleware CORS跨域中间件
func CORSMiddleware() gin.HandlerFunc {
	return func(c *gin.Context) {
		c.Header("Access-Control-Allow-Origin", "*")
		c.Header("Access-Control-Allow-Credentials", "true")
		c.Header("Access-Control-Allow-Headers", "Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization, accept, origin, Cache-Control, X-Requested-With")
		c.Header("Access-Control-Allow-Methods", "POST, OPTIONS, GET, PUT, DELETE")
		
		if c.Request.Method == "OPTIONS" {
			c.AbortWithStatus(204)
			return
		}
		
		c.Next()
	}
}

// AuthMiddleware 简单认证中间件
func AuthMiddleware() gin.HandlerFunc {
	return func(c *gin.Context) {
		// 获取 Authorization 头
		authHeader := c.GetHeader("Authorization")
		
		// 检查是否有认证头
		if authHeader == "" {
			c.JSON(http.StatusUnauthorized, gin.H{
				"status":  "error",
				"message": "缺少认证信息",
			})
			c.Abort() // 终止后续处理
			return
		}
		
		// 简单的 token 验证(实际项目中应该更复杂)
		if !strings.HasPrefix(authHeader, "Bearer ") {
			c.JSON(http.StatusUnauthorized, gin.H{
				"status":  "error",
				"message": "认证格式错误",
			})
			c.Abort()
			return
		}
		
		token := strings.TrimPrefix(authHeader, "Bearer ")
		if token != "your-secret-token" { // 实际应该查询数据库验证
			c.JSON(http.StatusUnauthorized, gin.H{
				"status":  "error",
				"message": "无效的认证令牌",
			})
			c.Abort()
			return
		}
		
		// 将用户信息存储到上下文中
		c.Set("user_id", "12345")
		c.Set("username", "testuser")
		
		c.Next() // 继续处理
	}
}

// RecoveryMiddleware 恢复中间件 - 捕获 panic
func RecoveryMiddleware() gin.HandlerFunc {
	return func(c *gin.Context) {
		defer func() {
			if err := recover(); err != nil {
				log.Printf("Panic recovered: %v", err)
				c.JSON(http.StatusInternalServerError, gin.H{
					"status":  "error",
					"message": "服务器内部错误",
				})
				c.Abort()
			}
		}()
		c.Next()
	}
}

// RateLimitMiddleware 简单限流中间件
func RateLimitMiddleware() gin.HandlerFunc {
	// 简单的内存存储(实际项目中应使用 Redis 等)
	requests := make(map[string][]time.Time)
	
	return func(c *gin.Context) {
		clientIP := c.ClientIP()
		now := time.Now()
		
		// 清理1分钟前的请求记录
		if requests[clientIP] != nil {
			var validRequests []time.Time
			for _, reqTime := range requests[clientIP] {
				if now.Sub(reqTime) < time.Minute {
					validRequests = append(validRequests, reqTime)
				}
			}
			requests[clientIP] = validRequests
		}
		
		// 检查是否超过限制(每分钟最多10次请求)
		if len(requests[clientIP]) >= 10 {
			c.JSON(http.StatusTooManyRequests, gin.H{
				"status":  "error",
				"message": "请求过于频繁,请稍后再试",
			})
			c.Abort()
			return
		}
		
		// 记录当前请求
		requests[clientIP] = append(requests[clientIP], now)
		
		c.Next()
	}
}

// RequestIDMiddleware 请求ID中间件
func RequestIDMiddleware() gin.HandlerFunc {
	return func(c *gin.Context) {
		// 生成请求ID
		requestID := fmt.Sprintf("%d", time.Now().UnixNano())
		
		// 设置响应头
		c.Header("X-Request-ID", requestID)
		
		// 存储到上下文
		c.Set("request_id", requestID)
		
		// 记录请求开始
		log.Printf("Request started: %s %s [Request-ID: %s]", 
			c.Request.Method, c.Request.URL.Path, requestID)
		
		c.Next()
		
		// 记录请求结束
		log.Printf("Request finished: %s [Request-ID: %s]", 
			c.Request.URL.Path, requestID)
	}
}

5.使用中间件

// main.go
package main

import (
	"net/http"
	
	"github.com/gin-gonic/gin"
	"your-project/middleware" // 替换为实际的包路径
	"your-project/handler"    // 替换为实际的包路径
)

func main() {
	// 创建 Gin 引擎
	r := gin.New()
	
	// 全局中间件
	r.Use(middleware.LoggerMiddleware())    // 日志中间件
	r.Use(middleware.RecoveryMiddleware())  // 恢复中间件
	r.Use(middleware.CORSMiddleware())      // CORS中间件
	r.Use(middleware.RequestIDMiddleware()) // 请求ID中间件
	
	// 公开路由(不需要认证)
	public := r.Group("/api/v1")
	{
		public.GET("/health", func(c *gin.Context) {
			c.JSON(http.StatusOK, gin.H{
				"status": "ok",
			})
		})
		public.POST("/login", handler.Login) // 登录接口不需要认证
	}
	
	// 需要认证的路由组
	private := r.Group("/api/v1")
	private.Use(middleware.AuthMiddleware()) // 认证中间件
	{
		private.GET("/users", handler.GetAllUsersWithPagination)
		private.POST("/users", handler.CreateUser)
		private.GET("/users/:id", handler.GetUserList)
	}
	
	// 需要限流的特定路由
	rateLimited := r.Group("/api/v1")
	rateLimited.Use(middleware.RateLimitMiddleware())
	{
		rateLimited.POST("/sensitive-operation", handler.SensitiveOperation)
	}
	
	// 启动服务器
	r.Run(":8080")
}

6.特定路由使用中间件

// 只对特定路由使用中间件
func SetupRoutes(r *gin.Engine) {
	// 不使用任何中间件的路由
	r.GET("/public", func(c *gin.Context) {
		c.JSON(200, gin.H{"message": "Public endpoint"})
	})
	
	// 使用单个中间件
	r.GET("/protected", middleware.AuthMiddleware(), func(c *gin.Context) {
		c.JSON(200, gin.H{"message": "Protected endpoint"})
	})
	
	// 使用多个中间件
	r.POST("/data", 
		middleware.AuthMiddleware(), 
		middleware.RateLimitMiddleware(),
		func(c *gin.Context) {
			c.JSON(200, gin.H{"message": "Protected and rate limited endpoint"})
		})
}

7.中间件实践

1.中间件分类

// 全局中间件 - 对所有请求生效
r.Use(LoggerMiddleware(), RecoveryMiddleware())

// 路由组中间件 - 对特定路由组生效
api := r.Group("/api")
api.Use(AuthMiddleware())

// 路由级别中间件 - 对单个路由生效
r.GET("/specific", RateLimitMiddleware(), handler.SpecificHandler)

2.中间件链执行

func ExampleMiddleware() gin.HandlerFunc {
	return func(c *gin.Context) {
		// 1. 请求前处理
		log.Println("Before request")
		
		// 2. 调用下一个中间件或处理函数
		c.Next()
		
		// 3. 响应后处理
		log.Println("After request")
		
		// 4. 可以访问处理结果
		status := c.Writer.Status()
		log.Printf("Response status: %d", status)
	}
}

3.中断请求处理

func AuthMiddleware() gin.HandlerFunc {
	return func(c *gin.Context) {
		if !isValidToken(c.GetHeader("Authorization")) {
			c.JSON(401, gin.H{"error": "Unauthorized"})
			c.Abort() // 中断处理链
			return
		}
		c.Next() // 继续处理
	}
}

网站公告

今日签到

点亮在社区的每一天
去签到