gin中间件(Use)不能写在响应函数之后的原因——源码分析

前言

 这个源码分析没什么意义,仅个人感兴趣进行探究而已

提出问题

 今天看别人写的gin代码的时候,发现中间件始终都是写在响应函数的上面

func main() {
	r := gin.Default()
	r.Use(wxf666)
	r.GET("/", func(c *gin.Context) {
		fmt.Println("Now in callback func")
		c.JSON(200, "首页")
	})
	r.Run(":8080")
}

 那能不能写在下面呢?

func main() {
	r := gin.Default()
	r.GET("/", func(c *gin.Context) {
		fmt.Println("Now in callback func")
		c.JSON(200, "首页")
	})
	r.Use(wxf666)
	r.Run(":8080")
}

先说结论,能写下面,但是不生效,即调用链不会调用wxf666这个函数

分析源码

初探----首先观察r.Get函数

 步入

r.GET("/", func(c *gin.Context))

 步入

group.handle(http.MethodGet, relativePath, handlers)

  步入,这里通过名称观察到handlers = group.combineHandlers(handlers),可能是添加调用链的地方,我们进去看看

func (group *RouterGroup) handle(httpMethod, relativePath string, handlers HandlersChain) IRoutes {
	absolutePath := group.calculateAbsolutePath(relativePath)
	handlers = group.combineHandlers(handlers)
	group.engine.addRoute(httpMethod, absolutePath, handlers)
	return group.returnObj()
}

  注意到这里返roup.Handlers是对外暴露的函数切片,这里将对外暴露的函数切片和传入的响应函数组合并返回,那么我们回到上层,看看给谁了

func (group *RouterGroup) combineHandlers(handlers HandlersChain) HandlersChain {
	finalSize := len(group.Handlers) + len(handlers)
	if finalSize >= int(abortIndex) {
		panic("too many handlers")
	}
	mergedHandlers := make(HandlersChain, finalSize)
	copy(mergedHandlers, group.Handlers)
	copy(mergedHandlers[len(group.Handlers):], handlers)
	return mergedHandlers
}

  发现新的调用链传递给了这一句,步入看看

group.engine.addRoute(httpMethod, absolutePath, handlers)

  相关的就是这一句,可以才想到这里就是将路径与调用链做了一个映射

root.addRoute(path, handlers)

再探----再次观察r.Use函数

  步入

r.Use(wxf666)

  步入第一句看看里面实现

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()
}

梳理流程

r.Get

mergedHandlers := make(HandlersChain, finalSize)
copy(mergedHandlers, group.Handlers)
copy(mergedHandlers[len(group.Handlers):], handlers)

r.Use

group.Handlers = append(group.Handlers, middleware...)

  其实到这里就已经能看出来了

问题总结

  如果r.Use写在r.Get前面,那么中间件函数就会在对外暴露的切片中了,一旦r.Get时,就会将copy(mergedHandlers, group.Handlers),此时中间件函数就被添加入调用链了

  而如果r.Use写在r.Get后面,那么copy(mergedHandlers, group.Handlers)的时候,中间件函数并不在对外暴露的函数切片中,所以没有被添加进调用链,最终只被添加进对外暴露的切片,始终没有被添加进调用链

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

cheems~

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值