本篇文章补充了中间件的使用,以及简单(简陋)的原理解析;
中间件的使用补充
中间件可以只在匹配一个路径时使用中间件,router.GET
函数中,第二个参数是可变参数,可以传入多个中间件
router.GET("/blog_detail.html", getBlogDetail, gin.Logger())
也可以分组匹配:
roup("/v1")
router.Use(gin.Logger())
{
router.GET("/blog", getBlogs)
}
自定义中间件
比如定义一个在方法执行前和执行后都打印提示的中间件
func MyLogger() gin.HandlerFunc {
return func(c *gin.Context) {
fmt.Println("请求开始处理。。。")
c.Next()
fmt.Println("请求处理结束。。。")
}
}
只在访问一个路径时使用:
router.GET("/blog_list.html", getBlogList, MyLogger())
效果:
gin中中间件有四个常用的方法:c.Next()、c.Abort()、c.Set()、c.Get();这里要注意的是c.Next方法,这个是执行后续中间件请求处理的意思,如果中间件拦截了这个请求后要在请求处理前后都有操作,就需要把c.Next()放到中间,调用c.Next会执行下一个中间件;像嵌套或者树的前序遍历一样,先往下执行,到底再往上返回;
原理浅析
中间件注册
首先看默认中间件的初始化实现流程:gin.Default():
func Default() *Engine {
debugPrintWARNINGDefault()
engine := New()
engine.Use(Logger(), Recovery()) // 默认注册两个中间件
return engine
}
继续查看engine.Use()函数的代码,其中调用engine.RouterGroup.Use
,HandlerFunc就是指中间件,这里可以传入多个中间件;
func (engine *Engine) Use(middleware ...HandlerFunc) IRoutes {
engine.RouterGroup.Use(middleware...) //调用的RouterGroup的Use函数
engine.rebuild404Handlers()
engine.rebuild405Handlers()
return engine
}
调用append()
就是将传入的中间件追加到group.Handlers
,而group.Handlers
就是HandlersChain类型,也就是一个切片:type HandlersChain []HandlerFunc
func (group *RouterGroup) Use(middleware ...HandlerFunc) IRoutes {
group.Handlers = append(group.Handlers, middleware...)
return group.returnObj()
}
实际注册路由时,会将对应路由的函数和中间件函数合并在一起,这个合并的过程也很有意思,创建一个长度等于中间件和路由函数的切片;用复制函数,把中间件函数复制到前面的部分,路由函数复制到后面的部分;
func (group *RouterGroup) combineHandlers(handlers HandlersChain) HandlersChain {
finalSize := len(group.Handlers) + len(handlers)
assert1(finalSize < int(abortIndex), "too many handlers")
mergedHandlers := make(HandlersChain, finalSize)
copy(mergedHandlers, group.Handlers)
copy(mergedHandlers[len(group.Handlers):], handlers)
return mergedHandlers
}
以上就是本篇文章的内容了,期待下次相遇。