一、Gin 中间件的洋葱模型图解
二、 流程控制
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
图示:
2.在中间件中调用Abort()
:
-
阻止请求向
内层中间件
乃至HandlerFunc
流动。 -
调用
Abort()
不会中止当前中间件函数的执行,除非后面跟着 return。
代码验证
将m2
的Next()
修改为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
图示
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
}