最近有個需求,就是發現我們的驗簽路由中間件會在判斷路由是否存在前執行。我們期望是gin框架先自己判斷路由中間件是否存在,存在了再走后面的中間件,不存在直接返回404.這樣能節省一定的資源。
研究了一下gin框架的源碼,
先說一下表面的研究。
當我用r.Use的方式直接注冊路由的時候,會是先走驗證中間件后走找路由。
當我先group再用group 去注冊路由的時候,就會是先找路由再走驗證中間件。
然后研究gin的use源碼。
這個是gin.Default的use源碼
func (engine *Engine) Use(middleware ...HandlerFunc) IRoutes {engine.RouterGroup.Use(middleware...)engine.rebuild404Handlers()engine.rebuild405Handlers()return engine
}
這個是group的use源碼
// Use adds middleware to the group, see example code in GitHub.
func (group *RouterGroup) Use(middleware ...HandlerFunc) IRoutes {group.Handlers = append(group.Handlers, middleware...)return group.returnObj()
}
可以看到gin.Default的use里面其實是直接調用了group的use,然后走了rebuild404Handler和rebuild405Handlers 方法。然后從函數名上就可以看出應該是rebuild404Handler 重置了判斷路由是否存在的流程運行位置。
下面是
func (engine *Engine) rebuild404Handlers() {engine.allNoRoute = engine.combineHandlers(engine.noRoute)
}
然后combineHandlers
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
}
從combineHandlers 里面的代碼可以看出不來,這里其實做了一個操作就是將將原來的allNoRoute 給替換掉了。新的allNoRoute 是將當前的handle組和engine.noRoute 合并起來的一個新allNoRoute 。
所以只要你是直接使用r.Use()那么你注冊的路由中間件都是在路由查詢之前跑的。改也很簡單,要么設置路由組,要么使用r.RouterGroup.Use()來注冊路由。