深入理解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的運(yùn)行機(jī)制。
到此這篇關(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-08
Go語言集成開發(fā)環(huán)境IDE詳細(xì)安裝教程
VSCode是免費開源的現(xiàn)代化輕量級代碼編輯器,支持幾乎所有主流的開發(fā)語言,內(nèi)置命令行工具和 Git 版本控制系統(tǒng),支持插件擴(kuò)展,這篇文章主要介紹了Go語言集成開發(fā)環(huán)境IDE詳細(xì)安裝教程,需要的朋友可以參考下2021-11-11

