Use(middleware …HandlerFunc)
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的尾部;
// group.Handlers的类型就是[]HandlerFunc
group.Handlers = append(group.Handlers, middleware...)
return group.returnObj()
}
每次再集成中间件的时候都会把中间件添加到group.Handlers的尾部;等到执行的时候,按照顺序执行集成的中间件
添加一个路由
package main
import (
"github.com/gin-gonic/gin"
"net/http"
)
func main() {
r := gin.New()
r.Use(gin.Logger(), gin.Recovery())
r.GET("/ping", func(context *gin.Context) {
context.JSON(http.StatusOK, gin.H{
"result": "pong",
})
})
_ = r.Run(":8081")
}
// GET添加路由
func (group *RouterGroup) GET(relativePath string, handlers ...HandlerFunc) IRoutes {
return group.handle(http.MethodGet, relativePath, handlers)
}
func (group *RouterGroup) handle(httpMethod, relativePath string, handlers HandlersChain) IRoutes {
absolutePath := group.calculateAbsolutePath(relativePath)
// 调用combineHandlers处理当前路由的func
handlers = group.combineHandlers(handlers)
group.engine.addRoute(httpMethod, absolutePath, handlers)
return group.returnObj()
}
func (group *RouterGroup) combineHandlers(handlers HandlersChain) HandlersChain {
// 将已有的中间件与当前传递过来的func进行相加
finalSize := len(group.Handlers) + len(handlers)
if finalSize >= int(abortIndex) {
// 对中间件的个数进行判断;禁止超过math.MaxInt8 / 2
panic("too many handlers")
}
// 通过个数校验后;创建一个新的切片;
// 并将group.Handlers中所有的元素按顺序放置到新的切片里面
// 将传递过来的func追加至最后
mergedHandlers := make(HandlersChain, finalSize)
copy(mergedHandlers, group.Handlers)
copy(mergedHandlers[len(group.Handlers):], handlers)
return mergedHandlers
}
Next()
func (c *Context) Next() {
// 将当前索引后移一位
c.index++
for c.index < int8(len(c.handlers)) {
// 如果索引不越界;就执行后移过的中间件
c.handlers[c.index](c)
// 执行完毕继续将索引后移一位
c.index++
}
}
当调用Next()时,就会将*RouterGroup.Handlers的当前索引向后移,判断是否越界;如果没有越界就继续执行当前索引的中间件;执行完毕继续后移;直至越界…;
再中间件里面使用return是不会影响整个队列的中间件执行的,return结束掉的只是当前函数(中间件);即使没有再中间件里面调用到Next()就return,c.index没有进行改变;也不会影响整个队列的执行;gin内部会驱动着整个队列的运行
Abort()
func (c *Context) Abort() {
// 将c.index标记为abortIndex;
// 这样后续的中间件包括请求本身都不会再执行了
c.index = abortIndex
}