Go Fiber 框架系列教程 03:中間件
閱讀本文大概需要 10?分鐘。
大家好,我是 polarisxu。
Middleware(中間件) 是一個(gè) Web 框架重要的組成部分,通過(guò)這種模式,可以方便的擴(kuò)展框架的功能。目前 Go Web 框架都提供了 Middleware 的功能,也有眾多可用的 Middleware。
Fiber 也是如此,官方提供了眾多的 Middleware,方便用戶(hù)直接使用。本文先看看 Fiber 中 Middleware 的定義,然后介紹 Fiber 中的幾個(gè) Middleware,最后自己實(shí)現(xiàn)一個(gè) Middleware。
Fiber 文檔中關(guān)于 Middleware 的說(shuō)明:中間件是在 HTTP 請(qǐng)求周期中鏈接的函數(shù),它可以訪(fǎng)問(wèn)用于執(zhí)行特定操作(例如,記錄每個(gè)請(qǐng)求或啟用 CORS)的上下文。
01 Middleware 長(zhǎng)什么樣
設(shè)計(jì)用于更改請(qǐng)求或響應(yīng)的函數(shù)稱(chēng)為中間件函數(shù)。Next 是 Fiber 路由器函數(shù),當(dāng)它被調(diào)用時(shí),執(zhí)行與當(dāng)前路由匹配的下一個(gè)函數(shù)。
可見(jiàn),中間件其實(shí)和 Handler 是一樣的,只是用途有區(qū)別?;蛘哒f(shuō)至少簽名是一樣的,這樣才能更好的形成一個(gè)鏈。
因此,F(xiàn)iber 中的中間件簽名如下:
func(ctx?*fiber.Ctx)?error
Fiber 沒(méi)有專(zhuān)門(mén)定義中間件類(lèi)型。
此外,從 fiber.App.Use 方法也可以看到,中間件和普通的 Handler 并無(wú)本質(zhì)不同。
//?Use?registers?a?middleware?route?that?will?match?requests
//?with?the?provided?prefix?(which?is?optional?and?defaults?to?"/").
//
//??app.Use(func(c?*fiber.Ctx)?error?{
//???????return?c.Next()
//??})
//??app.Use("/api",?func(c?*fiber.Ctx)?error?{
//???????return?c.Next()
//??})
//??app.Use("/api",?handler,?func(c?*fiber.Ctx)?error?{
//???????return?c.Next()
//??})
//
//?This?method?will?match?all?HTTP?verbs:?GET,?POST,?PUT,?HEAD?etc...
func?(app?*App)?Use(args?...interface{})?Router?{
?var?prefix?string
?var?handlers?[]Handler
?for?i?:=?0;?i?len(args);?i++?{
??switch?arg?:=?args[i].(type)?{
??case?string:
???prefix?=?arg
??case?Handler:
???handlers?=?append(handlers,?arg)
??default:
???panic(fmt.Sprintf("use:?invalid?handler?%v\n",?reflect.TypeOf(arg)))
??}
?}
?app.register(methodUse,?prefix,?handlers...)
?return?app
}
而 fiber.Handler 類(lèi)型只是 func(*fiber.Ctx) error 的別名:
//?Handler?defines?a?function?to?serve?HTTP?requests.
type?Handler?=?func(*Ctx)?error
這點(diǎn)上,Gin 框架和 Fiber 是類(lèi)似的。不過(guò),有一些框架,比如 Echo,專(zhuān)門(mén)定義了中間件類(lèi)型。但不管怎么樣,中間件的本質(zhì)和普通路由 Handler 是類(lèi)似的。
02 Fiber 內(nèi)置的中間件
所有內(nèi)置的中間件可以在 fiber 項(xiàng)目的 middleware 子包找到,這些中間件對(duì)應(yīng)的文檔在這里:https://docs.gofiber.io/api/middleware。
以 Recover 中間件為例,看看官方中間件的實(shí)現(xiàn)方法,我們自己的中間件可以參照實(shí)現(xiàn)。
1)簽名
func?New(config?...Config)?fiber.Handler
上文說(shuō)了,中間件就是一個(gè) Handler,因此這里 New 函數(shù)返回 fiber.Handler,這就中間件。
至于 New 函數(shù)的參數(shù)不做任何要求,只需要最終返回 fiber.Handler 即可。
2)配置
一個(gè)好的中間件,或通用的中間件,一般都會(huì)有配置,讓中間件更靈活、更強(qiáng)大??纯?Recover 的配置定義:
//?Config?defines?the?config?for?middleware.
type?Config?struct?{
????//?Next?defines?a?function?to?skip?this?middleware?when?returned?true.
????//
????//?Optional.?Default:?nil
????Next?func(c?*fiber.Ctx)?bool
????//?EnableStackTrace?enables?handling?stack?trace
????//
????//?Optional.?Default:?false
????EnableStackTrace?bool
????//?StackTraceHandler?defines?a?function?to?handle?stack?trace
????//
????//?Optional.?Default:?defaultStackTraceHandler
????StackTraceHandler?func(e?interface{})
}
具體配置是什么樣的,需要根據(jù)中間件的功能來(lái)定義。
不過(guò),配置中 Next 這個(gè)行為,很多中間件都可以有。
3)默認(rèn)配置
一般的,會(huì)提供一個(gè)默認(rèn)配置,方便使用。而且,大部分時(shí)候,使用默認(rèn)配置即可。Recover 的默認(rèn)配置如下:
var?ConfigDefault?=?Config{
????Next:??????????????nil,
????EnableStackTrace:??false,
????StackTraceHandler:?defaultStackTraceHandler,
}
如果這樣調(diào)用 recover.New() ,會(huì)默認(rèn)使用上面的默認(rèn)配置。
最后看看 New 函數(shù)的代碼:
//?New?creates?a?new?middleware?handler
func?New(config?...Config)?fiber.Handler?{
?//?Set?default?config
?cfg?:=?configDefault(config...)
?//?Return?new?handler
?return?func(c?*fiber.Ctx)?(err?error)?{
??//?Don't?execute?middleware?if?Next?returns?true
??if?cfg.Next?!=?nil?&&?cfg.Next(c)?{
???return?c.Next()
??}
??//?Catch?panics
??defer?func()?{
???if?r?:=?recover();?r?!=?nil?{
????if?cfg.EnableStackTrace?{
?????cfg.StackTraceHandler(r)
????}
????var?ok?bool
????if?err,?ok?=?r.(error);?!ok?{
?????//?Set?error?that?will?call?the?global?error?handler
?????err?=?fmt.Errorf("%v",?r)
????}
???}
??}()
??//?Return?err?if?exist,?else?move?to?next?handler
??return?c.Next()
?}
}
以上就是一個(gè) Fiber 標(biāo)準(zhǔn)中間件的寫(xiě)法。
具體使用時(shí)就是:app.Use(recover.New())。
當(dāng)然,如果只是自己項(xiàng)目使用,可以不用寫(xiě)配置。
03 實(shí)現(xiàn)一個(gè)簡(jiǎn)單的中間件
通過(guò) Recover 學(xué)習(xí)到了中間件的標(biāo)準(zhǔn)寫(xiě)法,如果中間件只在自己項(xiàng)目使用,不需要靈活性,完全可以采用簡(jiǎn)單的寫(xiě)法。
func?Security(ctx?*fiber.Ctx)?error?{
??ctx.Set("X-XSS-Protection",?"1;?mode=block")
??ctx.Set("X-Content-Type-Options",?"nosniff")
??ctx.Set("X-Download-Options",?"noopen")
??ctx.Set("Strict-Transport-Security",?"max-age=5184000")
??ctx.Set("X-Frame-Options",?"SAMEORIGIN")
??ctx.Set("X-DNS-Prefetch-Control",?"off")
??//?執(zhí)行下一個(gè)?Handler
??return?ctx.Next()
}
這其實(shí)也是一個(gè) Handler,對(duì)吧。無(wú)非最后調(diào)用的是 ctx.Next,而不是 ctx.JSON 之類(lèi)的。
使用時(shí)這樣:
app?:=?fiber.New()
app.Use(Security)
只要理解中間件的機(jī)制,不需要拘泥于具體形式,可以靈活變換中間件的寫(xiě)法。
04 總結(jié)
本文講解了什么是中間件,F(xiàn)iber 中間件長(zhǎng)什么樣以及對(duì)內(nèi)置中間件 Recover 的學(xué)習(xí),最后自己實(shí)現(xiàn)一個(gè)簡(jiǎn)單的中間件。掌握了 Fiber 的中間件,相信對(duì)其他 Go Web 框架的中間件的學(xué)習(xí)也就不難了,因?yàn)槎疾畈欢唷?/p>
我是 polarisxu,北大碩士畢業(yè),曾在 360 等知名互聯(lián)網(wǎng)公司工作,10多年技術(shù)研發(fā)與架構(gòu)經(jīng)驗(yàn)!2012 年接觸 Go 語(yǔ)言并創(chuàng)建了 Go 語(yǔ)言中文網(wǎng)!著有《Go語(yǔ)言編程之旅》、開(kāi)源圖書(shū)《Go語(yǔ)言標(biāo)準(zhǔn)庫(kù)》等。
堅(jiān)持輸出技術(shù)(包括 Go、Rust 等技術(shù))、職場(chǎng)心得和創(chuàng)業(yè)感悟!歡迎關(guān)注「polarisxu」一起成長(zhǎng)!也歡迎加我微信好友交流:gopherstudio
