中间件是 Gin 框架的精髓之一,理解它的工作原理对写出优雅的代码至关重要。
中间件是位于请求和处理器之间的函数,可以在请求到达处理器之前或之后执行代码。典型的用途包括:
一个中间件就是一个返回 gin.HandlerFunc 的函数:
package main
import (
"fmt"
"time"
"github.com/gin-gonic/gin"
)
func Logger() gin.HandlerFunc {
return func(c *gin.Context) {
start := time.Now()
c.Next()
duration := 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,
duration,
)
}
}
func main() {
r := gin.New()
r.Use(Logger())
r.GET("/hello", func(c *gin.Context) {
c.String(200, "Hello, World!")
})
r.Run(":8080")
}
c.Next() 是中间件的核心,它会把请求传递给下一个中间件或处理器:
func Middleware1() gin.HandlerFunc {
return func(c *gin.Context) {
fmt.Println("Middleware1 - 请求前")
c.Next()
fmt.Println("Middleware1 - 请求后")
}
}
func Middleware2() gin.HandlerFunc {
return func(c *gin.Context) {
fmt.Println("Middleware2 - 请求前")
c.Next()
fmt.Println("Middleware2 - 请求后")
}
}
r.Use(Middleware1())
r.Use(Middleware2())
r.GET("/test", func(c *gin.Context) {
fmt.Println("处理器执行")
c.String(200, "OK")
})
访问 /test 的输出顺序:
Middleware1 - 请求前
Middleware2 - 请求前
处理器执行
Middleware2 - 请求后
Middleware1 - 请求后
这就是所谓的"洋葱模型":请求从外层进入,响应从内层返回。
有时候需要在中间件里中断请求,比如权限验证失败:
func Auth() gin.HandlerFunc {
return func(c *gin.Context) {
token := c.GetHeader("Authorization")
if token == "" {
c.JSON(401, gin.H{"error": "未授权"})
c.Abort()
return
}
if !validateToken(token) {
c.JSON(403, gin.H{"error": "无效的令牌"})
c.Abort()
return
}
c.Next()
}
}
func validateToken(token string) bool {
return token == "valid-token"
}
r.Use(Auth())
r.GET("/protected", func(c *gin.Context) {
c.JSON(200, gin.H{"message": "访问成功"})
})
调用 c.Abort() 后,后续的中间件和处理器都不会执行。
Gin 提供了更简洁的中断方法:
func Auth() gin.HandlerFunc {
return func(c *gin.Context) {
token := c.GetHeader("Authorization")
if token == "" {
c.AbortWithStatusJSON(401, gin.H{"error": "未授权"})
return
}
c.Next()
}
}
常用的中断方法:
c.Abort()
c.AbortWithStatus(401)
c.AbortWithStatusJSON(401, gin.H{"error": "未授权"})
中间件按照注册顺序执行:
r.Use(MiddlewareA())
r.Use(MiddlewareB())
r.Use(MiddlewareC())
请求流程:A前 → B前 → C前 → 处理器 → C后 → B后 → A后
gin.Default() 默认添加了 Logger 和 Recovery 中间件:
func Default() *Engine {
engine := New()
engine.Use(Logger(), Recovery())
return engine
}
如果不需要这些默认中间件,使用 gin.New() 创建实例。
中间件是 Gin 框架的核心特性,通过 c.Next() 和 c.Abort() 控制请求流程。理解洋葱模型对正确使用中间件很重要。下一章我们会学习如何在不同范围内应用中间件。