深入理解Go Gin框架中間件的實現(xiàn)原理
中間件的實現(xiàn)原理
中間件的實現(xiàn)有:鏈?zhǔn)秸{(diào)用, 攔截器,注冊中心等方式,Gin框架使用的是 鏈?zhǔn)秸{(diào)用+ 洋蔥模型 。
鏈?zhǔn)秸{(diào)用
鏈?zhǔn)秸{(diào)用,顧名思義就是像一個鏈子一樣連在一起,一個一個的別調(diào)用。
Gin框架中的鏈是一個切片:
// HandlerFunc將gin中間件使用的處理程序定義為返回值。 type HandlerFunc func(*Context) //HandlersChain定義HandlerFunc切片。 type HandlersChain []HandlerFunc
一個路由需要經(jīng)歷的所有中間件函數(shù)以及最終的處理函數(shù)都會被按照添加的順序添加到函數(shù)鏈中并儲存在路由樹的節(jié)點上。
怎么調(diào)用中間件
在Gin中實現(xiàn)了http包的Handler接口的ServerHTTP方法,(調(diào)用流程在Gin啟動和接收請求的文章中介紹)。經(jīng)過ServerHTTP方法,初始化了Context結(jié)構(gòu)體,給其中index這個字段設(shè)為-1,調(diào)用c.Next時會調(diào)用到中間件函數(shù)。
ServerHTTP
// ServeHTTP實現(xiàn)http.Handler接口。 func (engine *Engine) ServeHTTP(w http.ResponseWriter, req *http.Request) { c := engine.pool.Get().(*Context) c.writermem.reset(w) c.Request = req c.reset()//初始化Context engine.handleHTTPRequest(c)//在這里邊調(diào)用了c.Next(), engine.pool.Put(c) }
c.Next
// Next should be used only inside middleware. // It executes the pending handlers in the chain inside the calling handler. // See example in GitHub. func (c *Context) Next() { c.index++ for c.index < int8(len(c.handlers)) { c.handlers[c.index](c)//這個就是函數(shù)鏈,調(diào)用第index的函數(shù),參數(shù)為c。 c.index++ } }
c.Abort
在中間件中還有一個Abort函數(shù),作用是終止執(zhí)行。
// Abort阻止調(diào)用掛起的處理程序。請注意,這不會停止當(dāng)前處理程序。 //假設(shè)你有一個授權(quán)中間件,它驗證當(dāng)前請求是否被授權(quán)。 //如果授權(quán)失?。ɡ纾好艽a不匹配), //則調(diào)用Abort以確保不調(diào)用此請求的其余處理程序。 const abortIndex int8 = math.MaxInt8 >> 1 func (c *Context) Abort() { c.index = abortIndex }
洋蔥模型
就像這個洋蔥一樣,鏈?zhǔn)胶瘮?shù)是一層一層的調(diào)用的。
我們看一下Gin框架官方的兩個中間件,他們很好的體現(xiàn)了洋蔥模型。
func Default() *Engine { debugPrintWARNINGDefault() engine := New() engine.Use(Logger(), Recovery()) return engine }
Logger
func Logger() HandlerFunc { return LoggerWithConfig(LoggerConfig{}) } func LoggerWithConfig(conf LoggerConfig) HandlerFunc { //省略初始化日志。 return func(c *Context) { ... c.Next() //省略將日志格式化輸出 } } }
通過前面我們知道,調(diào)用c.Next函數(shù)的時候會調(diào)用下一個函數(shù)鏈中下一個函數(shù),這時候LoggerWithConfig函數(shù)還沒有執(zhí)行完,就開始執(zhí)行下一個函數(shù)了,當(dāng)這個c.Next執(zhí)行完成后,才會去執(zhí)行下面的語句了。這個過程是不是就像是一層包一層,類似于洋蔥一樣。
Recovery
func Recovery() HandlerFunc { return RecoveryWithWriter(DefaultErrorWriter) } func RecoveryWithWriter(out io.Writer, recovery ...RecoveryFunc) HandlerFunc { if len(recovery) > 0 { return CustomRecoveryWithWriter(out, recovery[0]) } return CustomRecoveryWithWriter(out, defaultHandleRecovery) } func CustomRecoveryWithWriter(out io.Writer, handle RecoveryFunc) HandlerFunc { ... return func(c *Context) { defer func() { //基本功能是去捕獲異常的 }() c.Next() } }
Recovery的做作用是捕獲異常的,defer后的函數(shù)的作用是去捕獲c.Next函數(shù)后的異常,防止程序崩潰。具體原理可以去看看defer,painc和recovery的運行機制。
到此這篇關(guān)于深入理解Go Gin框架中間件的實現(xiàn)原理的文章就介紹到這了,更多相關(guān)Go Gin框架中間件內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Golang多線程排序?qū)崿F(xiàn)快速高效地處理大規(guī)模數(shù)據(jù)
Golang多線程排序是一種快速高效地處理大規(guī)模數(shù)據(jù)的方法,通過使用Golang的協(xié)程和通道,可以將排序任務(wù)分配到多個線程中并行處理,提高了排序的效率和速度,需要詳細(xì)了解可以參考下文2023-05-05詳解Go多協(xié)程并發(fā)環(huán)境下的錯誤處理
這篇文章主要介紹了詳解Go多協(xié)程并發(fā)環(huán)境下的錯誤處理,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-08-08Go語言集成開發(fā)環(huán)境IDE詳細(xì)安裝教程
VSCode是免費開源的現(xiàn)代化輕量級代碼編輯器,支持幾乎所有主流的開發(fā)語言,內(nèi)置命令行工具和 Git 版本控制系統(tǒng),支持插件擴展,這篇文章主要介紹了Go語言集成開發(fā)環(huán)境IDE詳細(xì)安裝教程,需要的朋友可以參考下2021-11-11