週末老王提了一個問題,若是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請求和結果。不過過於醜陋了。