周末老王提了一个问题,若是Gin中间件里面若是我忘记写context.Next了会有什么结果呢?git
我第一个反应是直接不会执行后面的handler了呗。我印象中gin的middleware也是个handler,而后维护一个handler链条,使用next进行调用传递。github
事实证实我错了,若是某个middleware里面忘记写c.Next(), 那么它仍是会进行后续调用的。只是不会再回到这个middleware中了。golang
这块代码又加深了一些理解:sql
func (c *Context) Next() { c.index++ for s := int8(len(c.handlers)); c.index < s; c.index++ { c.handlers[c.index](c) } }
每一个请求进来的时候,都已经建立了c.handlers数组,当第一个Next函数启动的时候,会进入到这里的for循环,在这个循环中,默认就是会调用全部的handler的。因此这里就回答了以前的问题,若是没有写next的话,就顺势进入到下一个排序的handler。数组
若是调用了Next的话呢,实际上就不会调度for循环里面的c.index++了,就进入了第一行的c.index++,而且调用下一个handler,由下一个handler里面的next进入第一行的c.index++。函数
这个设计确实有点反直觉。设计
可是看了这个帖子 https://github.com/gin-gonic/gin/issues/287 也就说了,c.Next其实不是必要的,它的必要性就是为了能执行Next函数后面的代码而已。日志
个人需求是一个请求用一个traceId进行串下来,无论是sql日志,仍是请求日志。code
这个想了老久了,最后结论:作不到orm
gorm是启动的时候就建立链接,而后每一个请求进来的时候,去链接池获取链接,进行请求。它的logger接口里面没有带上context,致使上下文丢失。
关键的代码在jinzhu/gorm/logger.go
type LogWriter interface { Println(v ...interface{}) } // Logger default logger type Logger struct { LogWriter } // Print format & print log func (logger Logger) Print(values ...interface{}) { logger.Println(LogFormatter(values...)...) }
这里的LogWriter并无使用上上下文。这个可能也只是因为gorm建立的时候尚未到go1.7。貌似又不少人也发现这个问题,但愿gorm加上context,https://github.com/jinzhu/gorm/issues/1231 可是至少如今还未加上去。
后来脑洞了一下,其实还有可能有一种作法,https://github.com/huandu/go-tls 像这种把context存储在goroutine做用域存储里面,而后建立一个自定义的Logger,在Print的时候,去这个goroutine做用域存储里面获取context。
可是这个建立goroutine做用域存储自己就是golang官网不提倡的。因而便做罢。。。
固然还有另一种办法,就是你本身在每次sql请求以后本身使用logger记录一下sql请求和结果。不过过于丑陋了。