Go Fiber 框架系列教程 02:詳解相關 API 的使用
大家好,我是 polarisxu。
該系列第一篇文章發出後,大家褒貶不一,很正常。選什麼,不選什麼,大家自己評估,沒有什麼是最好的。我這個系列,更多隻是讓大家對 Fiber 有些瞭解,說不定正好合你胃口呢?
前面對 Fiber 有了大概的印象。今天着重較深入探討 Fiber 相關功能。
先從 fiber.New
函數配置開始。
01 配置
大部分 Go 框架,獲得實例的函數是不支持配置的,比如 Gin、Echo 等。但 Fiber 框架的 New 函數支持傳遞配置:
// New creates a new Fiber named instance.
// app := fiber.New()
// You can pass optional configuration options by passing a Config struct:
// app := fiber.New(fiber.Config{
// Prefork: true,
// ServerHeader: "Fiber",
// })
func New(config ...Config) *App
一般情況,使用默認配置即可(即不手動傳遞配置),但有必要了解下,通過配置,我們能幹些什麼。
比如,我們希望響應頭中,Server 用自定義的。
config := fiber.Config{
ServerHeader: "Go Fiber Framework",
}
app := fiber.New(config)
響應頭類似這樣:
Content-Length: 12
Content-Type: text/plain; charset=utf-8
Date: Mon, 20 Sep 2021 14:58:45 GMT
Server: Go Fiber Framework
實際上,在前文模板引擎使用的 Views 就是一個配置項。
目前配置 29 項之多,有不少是關於 HTTP 的配置。所有的配置和說明可以在文檔找到:https://docs.gofiber.io/api/fiber#config。建議掃一遍,有一個印象,方便將來有需求時知道在這裏找。
02 路由
標準庫 net/http 的路由比較簡單,這大概也是有各種路由庫(框架)的原因之一。
最簡單的路由莫過於直接匹配,如:
// 請求匹配到 /about
app.Get("/about", func(c *fiber.Ctx) error {
return c.SendString("about")
})
而命名路由(也叫參數路由)是一個強大框架必須的,即提供佔位符。比如:
app.Get("/hello/:username", func(c *fiber.Ctx) error {
str := fmt.Sprintf("Hello, %s", c.Params("username"))
return c.SendString(str)
})
這個路由就可以匹配任意的以 /hello/
開頭的請求,比如:/hello/polarisxu
,最後會輸出:Hello, polarixu
。
不過,如果請求的剛好是 /hello/
呢?Fiber 會返回 404,報路由找不到。如果你希望這時候把 username 當空處理,而不是返回 404,可以在 :username
後加一個 ?
:
app.Get("/hello/:username?", func(c *fiber.Ctx) error {
str := fmt.Sprintf("Hello, %s", c.Params("username"))
return c.SendString(str)
})
此外,還有 +
和 *
進行通配,區別在於 +
要求至少要有一個,而 *
可以沒有。通過 c.Params("+")
和 c.Params("*")
獲得對於的值。
此外,Fiber 還支持有 -
和 .
的複雜路由,例如:
// http://localhost:3000/flights/LAX-SFO
app.Get("/flights/:from-:to", func(c *fiber.Ctx) error {
fmt.Fprintf(c, "%s-%s\n", c.Params("from"), c.Params("to"))
return nil // LAX-SFO
})
注意,如果路由中需要包含特殊字符,比如
:
,需要進行轉義。
因爲 Fiber 的目標之一是成爲 Go 最快、最清晰的 Web 框架,因此對於更復雜的路由,比如正則表達式,Fiber 不會支持。
Fiber 還提供了方法,返回所有註冊的路由信息:
var handler = func(c *fiber.Ctx) error { return nil }
func main() {
app := fiber.New()
app.Get("/john/:age", handler)
app.Post("/register", handler)
data, _ := json.MarshalIndent(app.Stack(), "", " ")
fmt.Println(string(data))
app.Listen(":3000")
}
返回結果如下:
[
[
{
"method": "GET",
"path": "/john/:age",
"params": [
"age"
]
}
],
[
{
"method": "HEAD",
"path": "/john/:age",
"params": [
"age"
]
}
],
[
{
"method": "POST",
"path": "/register",
"params": null
}
]
]
可以輔助排查路由問題。
03 Static
上文介紹了服務靜態資源的 Static 方法,這裏詳細解釋下。
Static 方法可以多個。默認情況下,如果目錄下有 index.html
文件,對目錄的訪問會以該文件作爲響應。
app.Static("/static/", "./public")
以上代碼用於項目根目錄下 public 目錄的文件和文件夾。
此外,Static 方法有第三個可選參數,以便對 Static 行爲進行微調,這可以通過 fiber.Static 結構體控制。
// Static defines configuration options when defining static assets.
type Static struct {
// When set to true, the server tries minimizing CPU usage by caching compressed files.
// This works differently than the github.com/gofiber/compression middleware.
// Optional. Default value false
Compress bool `json:"compress"`
// When set to true, enables byte range requests.
// Optional. Default value false
ByteRange bool `json:"byte_range"`
// When set to true, enables directory browsing.
// Optional. Default value false.
Browse bool `json:"browse"`
// The name of the index file for serving a directory.
// Optional. Default value "index.html".
Index string `json:"index"`
// Expiration duration for inactive file handlers.
// Use a negative time.Duration to disable it.
//
// Optional. Default value 10 * time.Second.
CacheDuration time.Duration `json:"cache_duration"`
// The value for the Cache-Control HTTP-header
// that is set on the file response. MaxAge is defined in seconds.
//
// Optional. Default value 0.
MaxAge int `json:"max_age"`
// Next defines a function to skip this middleware when returned true.
//
// Optional. Default: nil
Next func(c *Ctx) bool
}
上文說,默認情況下,對目錄訪問的索引文件是 index.html,通過 Index 可以改變該行爲。如果想要啓用目錄瀏覽功能,可以設置 Browse 爲 true。
04 路由處理器
在前面提到,Fiber 有對應的方法支持所有 HTTP Method。除此之外,還有兩個特殊的方法:Add 和 All。
Add 方法是所有 HTTP Method 對應方法的底層實現,比如 Get 方法:
func (app *App) Get(path string, handlers ...Handler) Router {
return app.Add(MethodHead, path, handlers...).Add(MethodGet, path, handlers...)
}
它底層調用了 Add 方法,做了兩次綁定,分別是 HEAD 和 GET,也就是說,對於 Get 方法,支持 HTTP GET 和 HEAD。
我之前寫過一篇文章:網友很強大,發現了 Go 併發下載的 Bug。Echo 框架,對於 Get 方法,只是 HTTP GET,不支持 HEAD 請求。目前看,Fiber 的做法更合理。如果你真的只需要 GET,可以通過 Add 方法實現。
而 All 方法表示支持任意 HTTP Method。
05 Mount 和 Group
Mount 方法可以將一個 Fiber 實例掛載到另一個實例。
func main() {
micro := fiber.New()
micro.Get("/doe", func(c *fiber.Ctx) error {
return c.SendStatus(fiber.StatusOK)
})
app := fiber.New()
app.Mount("/john", micro) // GET /john/doe -> 200 OK
log.Fatal(app.Listen(":3000"))
}
Group 是路由分組功能,框架基本會支持該特性,對於 API 版本控制很有用。
func main() {
app := fiber.New()
api := app.Group("/api", handler) // /api
v1 := api.Group("/v1", handler) // /api/v1
v1.Get("/list", handler) // /api/v1/list
v1.Get("/user", handler) // /api/v1/user
v2 := api.Group("/v2", handler) // /api/v2
v2.Get("/list", handler) // /api/v2/list
v2.Get("/user", handler) // /api/v2/user
log.Fatal(app.Listen(":3000"))
}
06 fiber.Ctx 的方法
此外,就是 handler 中的參數 fiber.Ctx,這是一個結構體,包含了衆多的方法(不少都是方便開發的方法),在使用時查閱 API 文檔,或訪問 https://docs.gofiber.io/api/ctx 瀏覽。
這裏介紹幾個其他框架可能沒有的方法。
// BodyParser binds the request body to a struct.
// It supports decoding the following content types based on the Content-Type header:
// application/json, application/xml, application/x-www-form-urlencoded, multipart/form-data
// If none of the content types above are matched, it will return a ErrUnprocessableEntity error
func (c *Ctx) BodyParser(out interface{}) error
該方法將請求綁定到結構體。(響應的也有 QueryParser 方法,主要處理查詢字符串到結構體的綁定)
看一個例子:
type Person struct {
Name string `json:"name" xml:"name" form:"name"`
Pass string `json:"pass" xml:"pass" form:"pass"`
}
app.Post("/login", func(ctx *fiber.Ctx) error {
p := new(Person)
if err := ctx.BodyParser(p); err != nil {
return err
}
log.Println(p.Name) // john
log.Println(p.Pass) // doe
return ctx.SendString("Success")
})
// 運行下面的命令進行測試
// curl -X POST -H "Content-Type: application/json" --data "{\"name\":\"john\",\"pass\":\"doe\"}" localhost:3000/login
// curl -X POST -H "Content-Type: application/xml" --data "<login><name>john</name><pass>doe</pass></login>" localhost:3000/login
// curl -X POST -H "Content-Type: application/x-www-form-urlencoded" --data " localhost:3000/login
// curl -X POST -F name=john -F pass=doe http://localhost:3000/login
// curl -X POST "http://localhost:3000/login?
關於獲取參數,包括路由參數、查詢參數、表單參數,Fiber 都非常友好的提供了可選的默認值形式,也就是說,當沒有傳遞對應值時,我們可以給一個默認值,比如:
// 10 是可選的。以下代碼表示,當 page 參數沒有傳遞,page=10
page := ctx.Query("page", 10)
默認值模式(可選參數)在 Fiber 中有大量使用,這能極大爲使用者帶來方便。
此外,路由參數還有 ParamsInt
方法,用來獲取 int 類型的路由參數。
07 小結
通過本文對 Fiber 內置功能的介紹,我的感受是,Fiber 爲開發者提供了很多便利。如果你沒有用過其他框架,可能沒有那麼大的感受。後續文章考慮出一個不同框架相關寫法的對比。
下篇文章介紹 Fiber 的中間件~
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/u0_wBhucMMzJYOwrZkV9IA