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

简介: 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)的时候,中间件函数并不在对外暴露的函数切片中,所以没有被添加进调用链,最终只被添加进对外暴露的切片,始终没有被添加进调用链


目录
相关文章
|
6月前
|
JSON 中间件 数据格式
Gin框架学习笔记(五) ——文件上传与路由中间件
Gin框架学习笔记(五) ——文件上传与路由中间件
|
消息中间件 负载均衡 中间件
【Alibaba中间件技术系列】「RocketMQ技术专题」让我们一起探索一下DefaultMQPullConsumer的实现原理及源码分析
【Alibaba中间件技术系列】「RocketMQ技术专题」让我们一起探索一下DefaultMQPullConsumer的实现原理及源码分析
199 2
【Alibaba中间件技术系列】「RocketMQ技术专题」让我们一起探索一下DefaultMQPullConsumer的实现原理及源码分析
|
算法 搜索推荐 中间件
Go Gin web框架的路由原理及中间件原理
Go Gin web框架的路由原理及中间件原理
788 13
Go Gin web框架的路由原理及中间件原理
|
前端开发 中间件 Java
Day05:Gin框架快速入门05 中间件和路由 | 青训营
Day05:Gin框架快速入门05 中间件和路由 | 青训营
|
中间件 开发者
史上最详细的Gin中间件使用教程
1.概述 Gin框架允许开发者在处理请求的过程中,加入用户自己的钩子(Hook)函数。这个钩子函数就叫中间件,中间件适合处理一些公共的业务逻辑,比如登录认证、权限校验、数据分页、记录日志、耗时统计等。
1083 14
史上最详细的Gin中间件使用教程
|
中间件 API Go
Gin增加超时控制中间件
Gin增加超时控制中间件
|
中间件 Go 数据格式
gin框架中间件深度解析
gin框架中间件深度解析
313 8
gin框架中间件深度解析
|
中间件 开发者
gin框架学习-路由分组和中间件
Logger中间件将日志写入gin.DefaultWriter,即使配置了GIN_MODE=release。
374 9
gin框架学习-路由分组和中间件
|
中间件
gin注册自定义中间件失效
gin注册自定义中间件失效
267 6
|
消息中间件 存储 负载均衡
【Alibaba中间件技术系列】「RocketMQ技术专题」让我们一起探索一下DefaultMQPushConsumer的实现原理及源码分析
【Alibaba中间件技术系列】「RocketMQ技术专题」让我们一起探索一下DefaultMQPushConsumer的实现原理及源码分析
204 6