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() // 继续处理
}
}