gin中间件详解|青训营

143 阅读2分钟

中间件

中间件原理

中间件是为了过滤路由而发明的一种机制,也就是http请求来到时先经过中间件,再到具体的处理函数。 下面是中间件的洋葱模型,请求到来时从最外层开始执行中间件1,然后进入第二层,依次执行完所有中间件最后到达主体函数,接着再一层一层的往外走再次执行中间件2…中间件1…最后返回。 IMG_1.png

中间件的注册

gin框架中的中间件设计很巧妙,我们可以首先从我们最常用的r := gin.Default()的Default函数开始看,它内部构造了一个新的engine之后就通过Use()函数注册了Logger中间件和Recovery中间件。 从use的代码中可以看出,注册中间件其实就是将中间件函数追加到group.Handlers中

func (group *RouterGroup) Use(middleware ...HandlerFunc) IRoutes {
	group.Handlers = append(group.Handlers, middleware...)
	return group.returnObj()
}

而我们注册路由时会将对应路由的函数和之前的中间件函数结合到一起:

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

也就是说,我们会将一个路由的中间件函数和处理函数结合到一起组成一条处理函数链条HandlersChain,而它本质上就是一个由HandlerFunc组成的切片

中间件执行

c.next()执行下一个函数

func (c *Context) Next() {
	c.index++
	for c.index < int8(len(c.handlers)) {//遍历HandlersChain链条
		c.handlers[c.index](c)
		c.index++
	}
}

c.abord()中断整个链条,从单前函数返回 c.set()/c.get() c.Set()和c.Get()这两个方法多用于在多个函数之间通过c传递数据的,比如我们可以在认证中间件中获取当前请求的相关信息(userID等)通过c.set()存入c, 然后在后续处理业务逻辑函数中通过c.Get()中获取当前请求的用户。c就像一根绳子,将该次请求相关的函数都串起来。

IMG_3.png

自定义中间件

我们可以通过自定义hunderfunc 方法来创建属于自己的中间件,并且通过use()部署在我们的服务中,例如 ``

func MyMiddleware(){
    return func(c *gin.Context){
    }
}

router = gin.Default()
router.Use(MyMiddleware())