highlight: xcode
简单介绍
Fiber 是一个受著名的 Node.js 的 Web Framework —— Express.js 启发的 Web 框架,建立在 Fasthttp 之上,Fasthttp 是 Go 最快的 HTTP 引擎。旨在简化快速开发,同时考虑零内存分配和性能。
安装
首先,需要下载并安装 Go SDK 1.17 或更高版本。
输入以下命令安装 Fiber:
shell go get github.com/gofiber/fiber/v2
零分配
Fiber 返回的某些值默认情况下,*fiber.Ctx
不是不可变的,可以在请求中重复使用。而且只能在处理程序中使用上下文值,你不能保留任何它们的引用。当你从 handler 程序返回之后,任何你从上下文中获取的值都可以在将来的请求中重复使用。实例如下:
```go func handler(c *fiber.Ctx) error { // Variable is only valid within this handler result := c.Params("foo")
// ...
} ``` 如果需要在 handler 外部对这样值进行持久化,使用内置的拷贝函数拷贝它们的缓冲区。示例如下:
```go func handler(c *fiber.Ctx) error { // Variable is only valid within this handler result := c.Params("foo")
// Make a copy
buffer := make([]byte, len(result))
copy(buffer, result)
resultCopy := string(buffer)
// Variable is now valid forever
// ...
} `` 以下示例编写了一个函数,在
gofiber/utils.CopyString` 函数下是可以用的。
```go app.Get("/:foo", func(c *fiber.Ctx) error { // Variable is now immutable result := utils.CopyString(c.Params("foo"))
// ...
}) ```
你也可以通过设置选项让上下文返回的值不可变,这会让你在任何地方持久化它们。当然,这会以性能作为代价。
go app := fiber.New(fiber.Config{ Immutable: true, })
第一个Hello World
使用 Fiber 内置的 New 函数可以快速构建一个 Web App:
```go package main
import "github.com/gofiber/fiber/v2"
func main() { app := fiber.New()
app.Get("/", func(c *fiber.Ctx) error {
return c.SendString("Hello, World!")
})
app.Listen(":3000")
} ```
输入以下命令启动应用程序:
shell go run server.go
通过浏览器访问 http://localhost:3000 返回 Hello, World!
字符串。
具体使用案例
路由
处理器
注册 HTTP 请求方式对应的处理函数:
```go // HTTP methods func (app *App) Get(path string, handlers ...Handler) Router func (app *App) Head(path string, handlers ...Handler) Router func (app *App) Post(path string, handlers ...Handler) Router func (app *App) Put(path string, handlers ...Handler) Router func (app *App) Delete(path string, handlers ...Handler) Router func (app *App) Connect(path string, handlers ...Handler) Router func (app *App) Options(path string, handlers ...Handler) Router func (app *App) Trace(path string, handlers ...Handler) Router func (app *App) Patch(path string, handlers ...Handler) Router
// Add allows you to specifiy a method as value func (app *App) Add(method, path string, handlers ...Handler) Router
// All will register the route on all HTTP methods // Almost the same as app.Use but not bound to prefixes func (app *App) All(path string, handlers ...Handler) Router ```
examples:
```go // Simple GET handler app.Get("/api/list", func(c *fiber.Ctx) error { return c.SendString("I'm a GET request!") })
// Simple POST handler app.Post("/api/register", func(c *fiber.Ctx) error { return c.SendString("I'm a POST request!") }) ```
Use
函数可以用于中间件包和前缀捕捉器。这些路由将仅仅匹配路径的起始字符串。/john
将会匹配 /john.doe
、/johnnnnn
等。
go func (app *App) Use(args ...interface{}) Router
examples:
```go // Match any request app.Use(func(c *fiber.Ctx) error { return c.Next() })
// Match request starting with /api app.Use("/api", func(c *fiber.Ctx) error { return c.Next() })
// Match requests starting with /api or /home (multiple-prefix support) app.Use([]string{"/api", "/home"}, func(c *fiber.Ctx) error { return c.Next() })
// Attach multiple handlers app.Use("/api", func(c *fiber.Ctx) error { c.Set("X-Custom-Header", random.String(32)) return c.Next() }, func(c *fiber.Ctx) error { return c.Next() }) ```
路由路径
和请求方法绑定到一起的路由路径定义了请求可以在哪里被处理。路由路径可以是固定的字符串或者是模式串。
examples:
```go // This route path will match requests to the root route, "/": app.Get("/", func(c *fiber.Ctx) error { return c.SendString("root") })
// This route path will match requests to "/about": app.Get("/about", func(c *fiber.Ctx) error { return c.SendString("about") })
// This route path will match requests to "/random.txt": app.Get("/random.txt", func(c *fiber.Ctx) error { return c.SendString("random.txt") }) ```
和 Express.js 框架一样,路由声明的顺序也发挥重要的作用。当一个请求被接收到,路由将会按照它们被声明的顺序进行检查。
请求参数
路由参数在路由中是动态元素,可以是具名或者是不具名的的部分。这些部分用于捕获 URL 中它们对应位置的值。以路径中具体的参数名位键,使用 Params
函数可以检索得到的值。
三种用于描述参数字符::
、+
、*
。贪心参数由通配符 *
或者 加号 +
表示。
路由规则还提供了使用可选参数的可能性,因为有的具名参数被标记了 ?
符号,不像 +
号它不是可选的。你可以使用通配符作为一个可选的贪婪的范围参数。
examples:
```go // Parameters app.Get("/user/:name/books/:title", func(c *fiber.Ctx) error { fmt.Fprintf(c, "%s\n", c.Params("name")) fmt.Fprintf(c, "%s\n", c.Params("title")) return nil }) // Plus - greedy - not optional app.Get("/user/+", func(c *fiber.Ctx) error { return c.SendString(c.Params("+")) })
// Optional parameter app.Get("/user/:name?", func(c *fiber.Ctx) error { return c.SendString(c.Params("name")) })
// Wildcard - greedy - optional app.Get("/user/", func(c *fiber.Ctx) error { return c.SendString(c.Params("")) })
// This route path will match requests to "/v1/some/resource/name:customVerb", // since the parameter character is escaped app.Get("/v1/some/resource/name\:customVerb", func(c *fiber.Ctx) error { return c.SendString("Hello, Community") })
// GET /@v1 // Params: "sign" -> "@", "param" -> "v1" app.Get("/:sign:param", handler)
// GET /api-v1 // Params: "name" -> "v1" app.Get("/api-:name", handler)
// GET /customer/v1/cart/proxy // Params: "1" -> "customer/", "2" -> "/cart" app.Get("/v1/proxy", handler)
// GET /v1/brand/4/shop/blue/xs // Params: "1" -> "brand/4", "2" -> "blue/xs" app.Get("/v1//shop/", handler) ```
参数约束
对应的参数还需要进行校验,如果跟对应的路由参数不匹配,Fiber 直接返回 404。这个特性是受到了 .NET Core 启发。
路由组
路径
像路由一样,路由组也可以有属于一簇的路径。
```go func main() { app := fiber.New()
api := app.Group("/api", middleware) // /api
v1 := api.Group("/v1", middleware) // /api/v1 v1.Get("/list", handler) // /api/v1/list v1.Get("/user", handler) // /api/v1/user
v2 := api.Group("/v2", middleware) // /api/v2 v2.Get("/list", handler) // /api/v2/list v2.Get("/user", handler) // /api/v2/user
log.Fatal(app.Listen(":3000")) } ```
一组路径可以有一个可选的处理器:
```go func main() { app := fiber.New()
api := app.Group("/api") // /api
v1 := api.Group("/v1") // /api/v1 v1.Get("/list", handler) // /api/v1/list v1.Get("/user", handler) // /api/v1/user
v2 := api.Group("/v2") // /api/v2 v2.Get("/list", handler) // /api/v2/list v2.Get("/user", handler) // /api/v2/user
log.Fatal(app.Listen(":3000")) } ```
组处理器
组处理器可以被用于作为路由路径但是它们必须得有一个 Next
方法这样的话流程才能继续走下去。
```go func main() { app := fiber.New()
handler := func(c *fiber.Ctx) error {
return c.SendStatus(fiber.StatusOK)
}
api := app.Group("/api") // /api
v1 := api.Group("/v1", func(c *fiber.Ctx) error { // middleware for /api/v1
c.Set("Version", "v1")
return c.Next()
})
v1.Get("/list", handler) // /api/v1/list
v1.Get("/user", handler) // /api/v1/user
log.Fatal(app.Listen(":3000"))
} ```
模板
Fiber 提供了一个 Views 接口可以为你提供你自己的模板引擎。
go type Views interface { Load() error Render(io.Writer, string, interface{}, ...string) error }
Views
接口包含了一个 Load
和 Render
方法,Load
在应用程序初始化的时候被 Fiber 执行以加载或者解析模板。
go // Pass engine to Fiber's Views Engine app := fiber.New(fiber.Config{ Views: engine, // Views Layout is the global layout for all template render until override on Render function. ViewsLayout: "layouts/main" })
Render
方法被链接到了 ctx.Render()
,并且接收一个模板名称和绑定的数据。如果在 Render
函数中没有定义布局,它会使用全局的布局。如果 Fiber 配置项 PassLocalToViews
被开启了,那么所有使用 ctx.Locals(key, value)
本地变量设置都会传递给模板。
go app.Get("/", func(c *fiber.Ctx) error { return c.Render("index", fiber.Map{ "hello": "world", }); })
引擎
Fiber 团队维护者模板包用来给模板引擎提供包装器:
```go package main
import ( "log" "github.com/gofiber/fiber/v2" "github.com/gofiber/template/html" )
func main() { // Initialize standard Go html template engine engine := html.New("./views", ".html") // If you want other engine, just replace with following // Create a new engine with django // engine := django.New("./views", ".django")
app := fiber.New(fiber.Config{
Views: engine,
})
app.Get("/", func(c *fiber.Ctx) error {
// Render index template
return c.Render("index", fiber.Map{
"Title": "Hello, World!",
})
})
log.Fatal(app.Listen(":3000"))
} ```