[Go Package] gin 中间件流程控制:c.Next() / c.Abort()

1,771 阅读1分钟

一、Gin 中间件的洋葱模型图解

image.png

二、 流程控制

1. 在中间件中调用Next():

  • 分割前置 / 后置拦截:Next()之前的代码会在到达HandlerFunc前执行,Next()方法之后的代码则在HandlerFunc处理后执行。
  • 数据传递:当前中间件调用next()请求 将交由内一层中间件。

代码验证

// MiddleWare1 定义中间件1
func MiddleWare1() gin.HandlerFunc {
   return func(c *gin.Context) {
      fmt.Println("前 m1")
      c.Next()
      fmt.Println("后 m1")
   }
}

// MiddleWare2 定义中间件2
func MiddleWare2() gin.HandlerFunc {
   return func(c *gin.Context) {
      fmt.Println("前 m2")
      c.Abort()
      fmt.Println("后 m2")
   }
}

// MiddleWare3 定义中间件3
func MiddleWare3() gin.HandlerFunc {
   return func(c *gin.Context) {
      fmt.Println("前 m3")
      c.Next()
      fmt.Println("后 m3")
   }
}

func main() {
   // 创建路由
   engine := gin.Default()

   // 注册中间件
   engine.Use(MiddleWare1(), MiddleWare2(), MiddleWare3())

   // 路由规则
   engine.GET("/", func(c *gin.Context) {
      fmt.Println("调用路由处理函数")
      // 页面接收
      c.JSON(200, gin.H{"msg": "路由处理函数被执行"})
   })
   err:=engine.Run(":3000")
   if err != nil {
      fmt.Println(err)
   }
}

//----------------
OutPut:
前 m1
前 m2
前 m3
调用路由处理函数
后 m3
后 m2
后 m1

图示:

image.png

2.在中间件中调用Abort():

  • 阻止请求向内层中间件乃至HandlerFunc流动。

  • 调用 Abort()不会中止当前中间件函数的执行,除非后面跟着 return。

代码验证

m2Next()修改为Abort() :


func M1() gin.HandlerFunc {
   return func(c *gin.Context) {
      fmt.Println("前 m1")
      c.Next()
      fmt.Println("后 m1")
   }
}

func M2() gin.HandlerFunc {
   return func(c *gin.Context) {
      fmt.Println("前 m2")
      
      `c.Abort()`
      
      fmt.Println("后 m2")
   }
}


func M3() gin.HandlerFunc {
   return func(c *gin.Context) {
      fmt.Println("前 m3")
      c.Next()
      fmt.Println("后 m3")
   }
}

func main() {
   // 创建路由
   engine := gin.Default()

   // 注册中间件
   engine.Use(MiddleWare1(), MiddleWare2(), MiddleWare3())

   // 路由规则
   engine.GET("/", func(c *gin.Context) {
      fmt.Println("调用路由处理函数")
      // 页面接收
      c.JSON(200, gin.H{"msg": "路由处理函数被执行"})
   })
   err:=engine.Run(":3000")
   if err != nil {
      fmt.Println(err)
   }
}
//--------OutPut:--------
前 m1
前 m2
后 m2   <--证明Abort()不会中止本函数,而是继续执行。
后 m1

图示

image.png

3.Next() / Abort()源码

// 调用 Next() 数据将转交给下一个中间件 
func (c *Context) Next() {
   c.index++
   for c.index < int8(len(c.handlers)) {
      c.handlers[c.index](c)
      c.index++
   }
}

//调用 Abort() 数据将不会流入内层中间件
func (c *Context) Abort() {
   c.index = abortIndex
}