中间件中的c.Next()与c.Abort()
理解这两个方法是掌握 Gin 中间件链式调用的关键。
c.Next() 执行原理
c.Next() 调用后续中间件和处理函数,等待其完成后继续执行:
Go
func timerMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
fmt.Println("1. 中间件开始")
start := time.Now()
c.Next() // 执行后续中间件和处理函数
fmt.Println("4. 中间件继续")
duration := time.Since(start)
fmt.Printf("耗时: %v\n", duration)
}
}
func handler(c *gin.Context) {
fmt.Println("2. 处理函数开始")
c.JSON(200, gin.H{"message": "ok"})
fmt.Println("3. 处理函数结束")
}
// 执行顺序输出:
// 1. 中间件开始
// 2. 处理函数开始
// 3. 处理函数结束
// 4. 中间件继续
中间件执行顺序
多个中间件按注册顺序形成调用链:
Go
r := gin.New()
r.Use(middlewareA())
r.Use(middlewareB())
r.GET("/test", handler)
// 执行顺序:
// A1 → B1 → Handler → B2 → A2
Go
func middlewareA() gin.HandlerFunc {
return func(c *gin.Context) {
fmt.Println("A1: 前置处理")
c.Next()
fmt.Println("A2: 后置处理")
}
}
func middlewareB() gin.HandlerFunc {
return func(c *gin.Context) {
fmt.Println("B1: 前置处理")
c.Next()
fmt.Println("B2: 后置处理")
}
}
// 输出:A1 → B1 → Handler → B2 → A2
c.Abort() 执行原理
c.Abort() 阻止后续中间件和处理函数执行:
Go
func authMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
token := c.GetHeader("Authorization")
if token == "" {
c.AbortWithStatus(401) // 终止后续执行
fmt.Println("认证失败,终止")
return // 当前函数继续执行到此结束
}
c.Next()
}
}
r.GET("/protected", authMiddleware(), handler)
// 无 token 时:认证失败 → 不执行 handler
// 有 token 时:认证成功 → 执行 handler
c.Abort() 常用方法
| 方法 | 说明 |
|---|---|
c.Abort() | 仅终止调用链 |
c.AbortWithStatus(code) | 终止并返回状态码 |
c.AbortWithStatusJSON(code, obj) | 终止并返回 JSON |
c.AbortWithError(code, err) | 终止并添加错误 |
Go
// 不同终止方式
c.Abort() // 无响应
c.AbortWithStatus(401) // 返回 401
c.AbortWithStatusJSON(401, gin.H{"error": "未认证"})
c.AbortWithError(500, errors.New("内部错误"))
判断是否被终止
Go
func loggingMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
c.Next()
if c.IsAborted() {
fmt.Println("请求已被终止")
}
status := c.Writer.Status()
fmt.Printf("状态码: %d\n", status)
}
}
组合使用示例
Go
func chainExample() {
r := gin.New()
r.Use(timerMiddleware())
r.Use(authMiddleware())
r.Use(permissionMiddleware())
r.GET("/admin", handler)
// 正常流程:timer → auth → permission → handler → permission → auth → timer
// 认证失败:timer → auth(abort) → timer(后置)
// 无权限:timer → auth → permission(abort) → auth → timer(后置)
}
不调用 c.Next() 的情况
Go
func blockingMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
c.JSON(200, gin.H{"message": "拦截"})
// 不调用 c.Next(),后续不执行
}
}
r.GET("/blocked", blockingMiddleware(), handler)
// 只执行 blockingMiddleware,handler 不执行
执行流程图
text
请求 → M1(前) → c.Next() → M2(前) → c.Next() → Handler → M2(后) → M1(后) → 响应
↓ c.Abort() ↑
请求 → M1(前) → M2(前) → 终止 → M1(后) → 401响应
c.Abort()后当前函数仍继续,需配合 return 完全终止。
要点总结
c.Next()调用后续处理,等待完成后继续执行当前函数c.Abort()阻止后续中间件和处理函数执行- 多个中间件形成洋葱模型:外层→内层→内层→外层
c.IsAborted()判断请求是否被终止c.Abort()后需要 return 终止当前中间件函数
📝 发现内容有误?点击此处直接编辑