Go Fiber 框架系列教程 03:中間件
大家好,我是 polarisxu。
Middleware(中間件) 是一個 Web 框架重要的組成部分,通過這種模式,可以方便的擴展框架的功能。目前 Go Web 框架都提供了 Middleware 的功能,也有衆多可用的 Middleware。
Fiber 也是如此,官方提供了衆多的 Middleware,方便用戶直接使用。本文先看看 Fiber 中 Middleware 的定義,然後介紹 Fiber 中的幾個 Middleware,最後自己實現一個 Middleware。
Fiber 文檔中關於 Middleware 的說明:中間件是在 HTTP 請求週期中鏈接的函數,它可以訪問用於執行特定操作(例如,記錄每個請求或啓用 CORS)的上下文。
01 Middleware 長什麼樣
設計用於更改請求或響應的函數稱爲中間件函數。Next 是 Fiber 路由器函數,當它被調用時,執行與當前路由匹配的下一個函數。
可見,中間件其實和 Handler 是一樣的,只是用途有區別。或者說至少簽名是一樣的,這樣才能更好的形成一個鏈。
因此,Fiber 中的中間件簽名如下:
func(ctx *fiber.Ctx) error
Fiber 沒有專門定義中間件類型。
此外,從 fiber.App.Use 方法也可以看到,中間件和普通的 Handler 並無本質不同。
// 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 類型只是 func(*fiber.Ctx) error
的別名:
// Handler defines a function to serve HTTP requests.
type Handler = func(*Ctx) error
這點上,Gin 框架和 Fiber 是類似的。不過,有一些框架,比如 Echo,專門定義了中間件類型。但不管怎麼樣,中間件的本質和普通路由 Handler 是類似的。
02 Fiber 內置的中間件
所有內置的中間件可以在 fiber 項目的 middleware 子包找到,這些中間件對應的文檔在這裏:https://docs.gofiber.io/api/middleware。
以 Recover 中間件爲例,看看官方中間件的實現方法,我們自己的中間件可以參照實現。
1)簽名
func New(config ...Config) fiber.Handler
上文說了,中間件就是一個 Handler,因此這裏 New 函數返回 fiber.Handler
,這就中間件。
至於 New 函數的參數不做任何要求,只需要最終返回 fiber.Handler
即可。
2)配置
一個好的中間件,或通用的中間件,一般都會有配置,讓中間件更靈活、更強大。看看 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{})
}
具體配置是什麼樣的,需要根據中間件的功能來定義。
不過,配置中 Next 這個行爲,很多中間件都可以有。
3)默認配置
一般的,會提供一個默認配置,方便使用。而且,大部分時候,使用默認配置即可。Recover 的默認配置如下:
var ConfigDefault = Config{
Next: nil,
EnableStackTrace: false,
StackTraceHandler: defaultStackTraceHandler,
}
如果這樣調用 recover.New()
,會默認使用上面的默認配置。
最後看看 New 函數的代碼:
// 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()
}
}
以上就是一個 Fiber 標準中間件的寫法。
具體使用時就是:app.Use(recover.New())
。
當然,如果只是自己項目使用,可以不用寫配置。
03 實現一個簡單的中間件
通過 Recover 學習到了中間件的標準寫法,如果中間件只在自己項目使用,不需要靈活性,完全可以採用簡單的寫法。
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")
// 執行下一個 Handler
return ctx.Next()
}
這其實也是一個 Handler,對吧。無非最後調用的是 ctx.Next,而不是 ctx.JSON 之類的。
使用時這樣:
app := fiber.New()
app.Use(Security)
只要理解中間件的機制,不需要拘泥於具體形式,可以靈活變換中間件的寫法。
04 總結
本文講解了什麼是中間件,Fiber 中間件長什麼樣以及對內置中間件 Recover 的學習,最後自己實現一個簡單的中間件。掌握了 Fiber 的中間件,相信對其他 Go Web 框架的中間件的學習也就不難了,因爲都差不多。
我是 polarisxu,北大碩士畢業,曾在 360 等知名互聯網公司工作,10 多年技術研發與架構經驗!2012 年接觸 Go 語言並創建了 Go 語言中文網!著有《Go 語言編程之旅》、開源圖書《Go 語言標準庫》等。
堅持輸出技術(包括 Go、Rust 等技術)、職場心得和創業感悟!歡迎關注「polarisxu」一起成長!也歡迎加我微信好友交流:gopherstudio
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/NL6MYQpvVOyJREiVX_DAgQ