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


目录
相关文章
|
1月前
|
JSON 中间件 Java
【GoGin】(3)Gin的数据渲染和中间件的使用:数据渲染、返回JSON、浅.JSON()源码、中间件、Next()方法
我们在正常注册中间件时,会打断原有的运行流程,但是你可以在中间件函数内部添加Next()方法,这样可以让原有的运行流程继续执行,当原有的运行流程结束后再回来执行中间件内部的内容。​ c.Writer.WriteHeaderNow()还会写入文本流中。可以看到使用next后,正常执行流程中并没有获得到中间件设置的值。接口还提供了一个可以修改ContentType的方法。判断了传入的状态码是否符合正确的状态码,并返回。在内部封装时,只是标注了不同的render类型。再看一下其他返回的类型;
149 3
|
消息中间件 负载均衡 中间件
【Alibaba中间件技术系列】「RocketMQ技术专题」让我们一起探索一下DefaultMQPullConsumer的实现原理及源码分析
【Alibaba中间件技术系列】「RocketMQ技术专题」让我们一起探索一下DefaultMQPullConsumer的实现原理及源码分析
339 86
【Alibaba中间件技术系列】「RocketMQ技术专题」让我们一起探索一下DefaultMQPullConsumer的实现原理及源码分析
|
中间件 开发者
gin框架学习-路由分组和中间件
Logger中间件将日志写入gin.DefaultWriter,即使配置了GIN_MODE=release。
560 91
gin框架学习-路由分组和中间件
|
中间件 Go 数据格式
gin框架中间件深度解析
gin框架中间件深度解析
483 80
gin框架中间件深度解析
|
JSON 中间件 数据格式
Gin框架学习笔记(五) ——文件上传与路由中间件
Gin框架学习笔记(五) ——文件上传与路由中间件
212 0
|
中间件
gin注册自定义中间件失效
gin注册自定义中间件失效
387 59
|
前端开发 中间件 Java
Day05:Gin框架快速入门05 中间件和路由 | 青训营
Day05:Gin框架快速入门05 中间件和路由 | 青训营
|
中间件 API Go
Gin增加超时控制中间件
Gin增加超时控制中间件
|
消息中间件 存储 中间件
【消息中间件】详解三大MQ:RabbitMQ、RocketMQ、Kafka
【消息中间件】详解三大MQ:RabbitMQ、RocketMQ、Kafka
11838 1

热门文章

最新文章