Gin 中的 next

func main() {
	r := gin.Default()
	r.Use(func(c *gin.Context) {
		fmt.Println(1, " ")
		c.Next()
		fmt.Println(6, " ")
	})
	r.Use(func(c *gin.Context) {
		fmt.Println(2, " ")
		fmt.Println(5, " ")
	})
	r.Use(func(c *gin.Context) {
		fmt.Println(3, " ")
		c.Next()
		fmt.Println(4, " ")
	})
	r.GET("/ping", func(c *gin.Context) {
		c.JSON(http.StatusOK, gin.H{
			"message": "pong",
		})
	})
	r.Run("localhost:8080")
}
// 打印 1 2 5 3 4 6

Gin 中使用 gin.go Use 函数注册中间件
最终调用 routergroup.go Use 函数, 放入 group.Handlers 队列中

func (engine *Engine) Use(middleware ...HandlerFunc) IRoutes {
	engine.RouterGroup.Use(middleware...)
	engine.rebuild404Handlers()
	engine.rebuild405Handlers()
	return engine
}

func (group *RouterGroup) Use(middleware ...HandlerFunc) IRoutes {
	group.Handlers = append(group.Handlers, middleware...)
	return group.returnObj()
}
func (c *Context) Next() {
	c.index++
	for c.index < int8(len(c.handlers)) {
		c.handlers[c.index](c)
		c.index++
	}
}

Next 函数中可以看到, 通过控制 index 来控制中间件的结束
并且默认在执行完上一个中间件之后, 即使不调用 Next 也会继续调用下一个中间件

const abortIndex int8 = math.MaxInt8 >> 1

func (c *Context) Abort() {
	c.index = abortIndex
}

在注册中间件时, 有个数量判断, 数量必须小于 abortIndex
所以在 Gin 里中断剩余中间件的方法 Abort 函数的实现是对 index 赋值

总结

  • 中间件代码无论是否有调用 Next() 方法,后续中间件也会执行
  • 中间件调用 Next() 方法之后, 会先执行后面的中间件最后再执行当前中间件的剩余代码
  • 中断剩余中间件需要使用 Abort() 方法, 但当前中间件的剩余代码以及调用了 Next() 的中间件的剩余代码还会继续执行