Fiber 是一个受 Express 启发的 web 框架,构建在 Go 最快的 HTTP 引擎 Fasthttp 上。旨在 为 快速 开发提供方便,同时考虑 零内存分配 和 性能。
路由
app.Get("/", func (c *fiber.Ctx) error {
return c.SendString("GET request")
})
app.Get("/:param", func (c *fiber.Ctx) error {
return c.SendString("param: " + c.Params("param"))
})
app.Post("/", func (c *fiber.Ctx) error {
return c.SendString("POST request")
})
app.Get("/:name?", func(c *fiber.Ctx) error {
if c.Params("name") != "" {
return c.SendString("Hello " + c.Params("name"))
}
return c.SendString("Where is john?")
})
// GET http://localhost:3000/api/user/john
app.Get("/api/*", func(c *fiber.Ctx) error {
return c.SendString("API path: " + c.Params("*"))
// => API path: user/john
})
静态文件
app.Static("/", "./public")
app.Static("/static", "./public")
API
app.Get("/api/posts", func (c *fiber.Ctx) error {
posts := getPosts() // your logic
if len(posts) == 0 {
return c.Status(404).JSON(&fiber.Map{
"success": false,
"error": "There are no posts!",
})
}
return c.JSON(&fiber.Map{
"success": true,
"posts": posts,
})
})
中间件
package main
import (
"log"
"github.com/gofiber/fiber/v2"
"github.com/gofiber/fiber/v2/middleware/cors"
)
func main() {
app := fiber.New()
app.Use(cors.New())
app.Use(func (c *fiber.Ctx) error {
if c.Is("json") {
return c.Next()
}
return c.SendString("Only JSON allowed!")
})
app.Get("/", func(c *fiber.Ctx) error {
return c.JSON(fiber.Map{
"message": "Hello World",
})
})
log.Fatal(app.Listen(":3000"))
}
模板引擎
Fiber支持多个模板引擎,例如Handlebars和Pug 。
package main
import (
"log"
"github.com/gofiber/fiber/v2"
"github.com/gofiber/template/html"
)
func main() {
app := fiber.New(fiber.Config{
Views: html.New("./views", ".html"),
})
app.Get("/", func(c *fiber.Ctx) error {
return c.Render("index", fiber.Map{
"Title": "Hello, World!",
})
})
log.Fatal(app.Listen(":3000"))
}
WebSocket
app.Get("/ws", websocket.New(func(c *websocket.Conn) {
// Websocket logic
for {
mtype, msg, err := c.ReadMessage()
if err != nil {
break
}
log.Printf("Read: %s", msg)
err = c.WriteMessage(mtype, msg)
if err != nil {
break
}
}
log.Println("Error:", err)
}))
速率限制器
package main
import (
"log"
"github.com/gofiber/fiber/v2"
"github.com/gofiber/fiber/v2/middleware/limiter"
)
func main() {
app := fiber.New()
// 每10秒最多3个请求
app.Use(limiter.New(limiter.Config{
Timeout: 10,
Max: 3,
}))
// ...
log.Fatal(app.Listen(":3000"))
}
Config
app := fiber.New(fiber.Config{
Prefork: true,
CaseSensitive: true,
StrictRouting: true,
ServerHeader: "Fiber",
})
属性 | 类型 | 解释 | 缺省 |
---|---|---|---|
Prefork | bool | 启用对SO_REUSEPORT套接字选项的使用。 这将产生多个Go进程在同一端口上侦听。 | false |
ServerHeader | string | 使用给定值启用服务器HTTP标头。 (服务器响应时,Server头的值) | |
StrictRouting | bool | 启用后,路由器会将 /foo 和 /foo/ 视为不同。否则,路由器会将 /foo和 /foo/ 视为相同。 | false |
CaseSensitive | bool | 启用后,/Foo 和 /foo 是不同的路由。 禁用后,/Foo 和 /foo被视为相同。(区分大小写) | false |
Immutable | bool | 启用后,上下文方法返回的所有值都是不可变的。 默认情况下,它们是有效的,直到您从处理程序中返回为止;否则,它们将一直有效。 | false |
UnescapePath | bool | 在设置上下文的路径之前,将路由中的所有编码字符转换回,以便路由也可以使用URL编码的特殊字符 | false |
ETag | bool | 启用或禁用ETag头生成,因为弱标签和强标签都是使用相同的哈希方法生成的(CRC-32)。弱etag是启用时的默认值。 | false |
BodyLimit | int | 设置请求正文的最大允许大小,如果大小超过配置的限制,它将发送413 -请求实体太大的响应。 | 4 * 1024 * 1024 |
Concurrency | int | 最大并发连接数。 | 256 * 1024 |
Views | Views | 视图是包装“渲染”功能的界面。 有关支持的引擎,请参见我们的模板中间件。 | nil |
ReadTimeout | time.Duration | 读取完整请求(包括正文)所允许的时间。 默认超时是无限的。 | nil |
WriteTimeout | time.Duration | 响应写超时前的最大持续时间。默认超时时间是无限的。 | nil |
IdleTimeout | time.Duration | 启用keep-alive时等待下一个请求的最大时间。“IdleTimeout”为0时,使用“ReadTimeout”的值。 | nil |
ReadBufferSize | int | 每个连接的缓冲区大小,用于读取请求。 这也限制了最大标头大小。 如果您的客户端发送多KB RequestURI和/或多KB标头(例如BIG cookie),则增加此缓冲区。 | 4096 |
WriteBufferSize | int | 用于写入响应的每个连接缓冲区大小。 | 4096 |
CompressedFileSuffix | string | 在原始文件名后添加一个后缀,然后尝试将生成的压缩文件保存在新文件名下。(?) | “.fiber.gz” |
ProxyHeader | string | 这将使c.p ip()返回给定头键的值。默认情况下,c.p IP()将从TCP连接返回远程IP,如果你在负载均衡器后面,这个属性会很有用,例如X-Forwarded-*。(获取真实IP) | |
GETOnly | bool | 如果设置为true,则拒绝所有非GET请求。 对于仅接受GET请求的服务器,此选项可用作反DoS保护。 如果设置了GETOnly,则请求大小受ReadBufferSize限制。 | false |
ErrorHandler | ErrorHandler | 当Fiber.Handler返回错误时,将执行ErrorHandler。| DefaultErrorHandler | | |
DisableKeepalive | bool | 禁用保持活动连接,服务器在向客户端发送第一个响应后将关闭传入连接 | false |
DisableDefaultDate | bool | 设置为true时,默认日期标题将从响应中排除。 | false |
DisableDefaultContentType | bool | 当设置为true时,将导致默认的Content-Type标头从Response中排除。 | false |
DisableHeaderNormalizing | bool | 默认情况下,所有头部名称都是规范化的:conteNT-tYPE -> conteNT-tYPE | false |
DisableStartupMessage | bool | 当设置为true时,它将不打印调试信息 | false |
NewError
NewError创建一个带有可选消息的新HTTPError实例。
app.Get("/", func(c *fiber.Ctx) error {
return fiber.NewError(782, "Custom error message")
})
IsChild
IsChild确定当前进程是否是Prefork的结果。
app := fiber.New(fiber.Config{
Prefork: true,
})
if !fiber.IsChild() {
fmt.Println("I'm the parent process")
} else {
fmt.Println("I'm a child process")
}
路由
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
可以用于中间件软件包和前缀捕获器。 这些路由只会匹配每个路径的开头,即/john将匹配/john/doe,/johnnnnn等
// 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()
})
// 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()
})
Mount
您可以通过创建一个*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"))
}
组
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"))
}
Server
返回基础的fasthttp服务器
func main() {
app := fiber.New()
app.Server().MaxConnsPerIP = 1
// ...
}
Stack
此方法返回原始路由器堆栈
var handler = func(c *fiber.Ctx) {}
func main() {
app := fiber.New()
app.Get("/john", handler)
app.Post("/register", handler)
data, _ := json.MarshalIndent(app.Stack(), "", " ")
fmt.Println(string(data))
}
输出以下内容
[
[
{
"method": "GET",
"path": "/john/:age",
"params": [
"age"
]
}
],
[
{
"method": "HEAD",
"path": "/john/:age",
"params": [
"age"
]
}
],
[
{
"method": "POST",
"path": "/register",
"params": null
}
]
]
ListenTLS
app.ListenTLS(":443", "./cert.pem", "./cert.key");
上下文
Accepts
检查指定的扩展名或内容类型是否可接受。
// Accept: text/*, application/json
app.Get("/", func(c *fiber.Ctx) error {
c.Accepts("html") // "html"
c.Accepts("text/html") // "text/html"
c.Accepts("json", "text") // "json"
c.Accepts("application/json") // "application/json"
c.Accepts("image/png") // ""
c.Accepts("png") // ""
// ...
})
// Accept-Charset: utf-8, iso-8859-1;q=0.2
// Accept-Encoding: gzip, compress;q=0.2
// Accept-Language: en;q=0.8, nl, ru
app.Get("/", func(c *fiber.Ctx) error {
c.AcceptsCharsets("utf-16", "iso-8859-1")
// "iso-8859-1"
c.AcceptsEncodings("compress", "br")
// "compress"
c.AcceptsLanguages("pt", "nl", "ru")
// "nl"
// ...
})
Append
将指定的值附加到HTTP响应标头字段。
app.Get("/", func(c *fiber.Ctx) error {
c.Append("Link", "http://google.com", "http://localhost")
// => Link: http://localhost, http://google.com
c.Append("Link", "Test")
// => Link: http://localhost, http://google.com, Test
// ...
})
Attachment
将HTTP响应的Content-Disposition标头字段设置为附件。
app.Get("/", func(c *fiber.Ctx) error {
c.Attachment()
// => Content-Disposition: attachment
c.Attachment("./upload/images/logo.png")
// => Content-Disposition: attachment; filename="logo.png"
// => Content-Type: image/png
// ...
})
App
返回*App引用,以便您可以轻松访问所有应用程序设置。
app.Get("/stack", func(c *fiber.Ctx) error {
return c.JSON(c.App().Stack())
})
BaseURL
以字符串形式返回基本URL(协议+主机)。
app.Get("/", func(c *fiber.Ctx) error {
c.BaseURL() // https://example.com
// ...
})
Body
// curl -X POST http://localhost:8080 -d user=john
app.Post("/", func(c *fiber.Ctx) error {
// Get raw body from POST request:
return c.Send(c.Body()) // []byte("user=john")
})
BodyParser
将请求主体绑定到结构。 BodyParser支持基于Content-Type标头对查询参数和以下内容类型进行解码:
// Field names should start with an uppercase letter
type Person struct {
Name string `json:"name" xml:"name" form:"name"`
Pass string `json:"pass" xml:"pass" form:"pass"`
}
app.Post("/", func(c *fiber.Ctx) error {
p := new(Person)
if err := c.BodyParser(p); err != nil {
return err
}
log.Println(p.Name) // john
log.Println(p.Pass) // doe
// ...
})
// Run tests with the following curl commands
// curl -X POST -H "Content-Type: application/json" --data "{\"name\":\"john\",\"pass\":\"doe\"}" localhost:3000
// curl -X POST -H "Content-Type: application/xml" --data "<login><name>john</name><pass>doe</pass></login>" localhost:3000
// curl -X POST -H "Content-Type: application/x-www-form-urlencoded" --data "name=john&pass=doe" localhost:3000
// curl -X POST -F name=john -F pass=doe http://localhost:3000
// curl -X POST "http://localhost:3000/?name=john&pass=doe"
ClearCookie
app.Get("/", func(c *fiber.Ctx) error {
c.ClearCookie() // 清除所有cookies
c.ClearCookie("user") // 按名称过期特定的cookie
c.ClearCookie("token", "session", "track_id", "version")
})
app.Get("/set", func(c *fiber.Ctx) error {
c.Cookie(&fiber.Cookie{
Name: "token",
Value: "randomvalue",
Expires: time.Now().Add(24 * time.Hour),
HTTPOnly: true,
SameSite: "lax",
})
// ...
})
app.Get("/delete", func(c *fiber.Ctx) error {
c.Cookie(&fiber.Cookie{
Name: "token",
// Set expiry date to the past
Expires: time.Now().Add(-(time.Hour * 2)),
HTTPOnly: true,
SameSite: "lax",
})
// ...
})
Cookie
type Cookie struct {
Name string `json:"name"`
Value string `json:"value"`
Path string `json:"path"`
Domain string `json:"domain"`
MaxAge int `json:"max_age"`
Expires time.Time `json:"expires"`
Secure bool `json:"secure"`
HTTPOnly bool `json:"http_only"`
SameSite string `json:"same_site"`
}
app.Get("/", func(c *fiber.Ctx) error {
// Create cookie
cookie := new(fiber.Cookie)
cookie.Name = "john"
cookie.Value = "doe"
cookie.Expires = time.Now().Add(24 * time.Hour)
// Set cookie
c.Cookie(cookie)
// ...
})
Cookies
通过键获取cookie值,您可以传递一个可选的默认值,如果cookie键不存在,则将返回该默认值。
app.Get("/", func(c *fiber.Ctx) error {
// Get cookie by key:
c.Cookies("name") // "john"
c.Cookies("empty", "doe") // "doe"
// ...
})
下载
将文件作为附件从路径中传输。
通常,浏览器会提示用户下载。 默认情况下,Content-Disposition标头的filename =参数是文件路径(通常显示在浏览器对话框中)。
使用filename参数覆盖此默认值。
app.Get("/", func(c *fiber.Ctx) error {
return c.Download("./files/report-12345.pdf");
// => Download report-12345.pdf
return c.Download("./files/report-12345.pdf", "report.pdf");
// => Download report.pdf
})
Request
app.Get("/", func(c *fiber.Ctx) error {
c.Request().Header.Method()
// => []byte("GET")
})
Response
app.Get("/", func(c *fiber.Ctx) error {
c.Response().Write([]byte("Hello, World!"))
// => "Hello, World!"
})
Format
在Accept HTTP标头上执行内容协商。 它使用接受来选择适当的格式。
app.Get("/", func(c *fiber.Ctx) error {
// Accept: text/plain
c.Format("Hello, World!")
// => Hello, World!
// Accept: text/html
c.Format("Hello, World!")
// => <p>Hello, World!</p>
// Accept: application/json
c.Format("Hello, World!")
// => "Hello, World!"
// ..
})
FormFile
可以按名称检索MultipartForm文件,并返回给定键的第一个文件。
app.Post("/", func(c *fiber.Ctx) error {
// Get first file from form field "document":
file, err := c.FormFile("document")
// Save file to root directory:
return c.SaveFile(file, fmt.Sprintf("./%s", file.Filename))
})
FormValue
可以通过名称检索任何表单值,返回给定键的第一个值。
app.Post("/", func(c *fiber.Ctx) error {
// Get first value from form field "name":
c.FormValue("name")
// => "john" or "" if not exist
// ..
})
Fresh
Get
返回由字段指定的HTTP请求头。
app.Get("/", func(c *fiber.Ctx) error {
c.Get("Content-Type") // "text/plain"
c.Get("CoNtEnT-TypE") // "text/plain"
c.Get("something", "john") // "john"
// ..
})
Hostname
// GET http://google.com/search
app.Get("/", func(c *fiber.Ctx) error {
c.Hostname() // "google.com"
})
IP
c.IP()
IPs
返回在X-Forwarded-For请求标头中指定的IP地址数组。
c.IPs() // ["proxy1", "127.0.0.1", "proxy3"]
Is
如果传入请求的Content-Type HTTP标头字段与type参数指定的MIME类型匹配,则返回匹配的内容类型
// Content-Type: text/html; charset=utf-8
app.Get("/", func(c *fiber.Ctx) error {
c.Is("html") // true
c.Is(".html") // true
c.Is("json") // false
})
JSON
type SomeStruct struct {
Name string
Age uint8
}
app.Get("/json", func(c *fiber.Ctx) error {
// Create data struct:
data := SomeStruct{
Name: "Grame",
Age: 20,
}
return c.JSON(data)
// => Content-Type: application/json
// => "{"Name": "Grame", "Age": 20}"
return c.JSON(fiber.Map{
"name": "Grame",
"age": 20,
})
// => Content-Type: application/json
// => "{"name": "Grame", "age": 20}"
})
JSONP
type SomeStruct struct {
name string
age uint8
}
app.Get("/", func(c *fiber.Ctx) error {
// Create data struct:
data := SomeStruct{
name: "Grame",
age: 20,
}
return c.JSONP(data)
// => callback({"name": "Grame", "age": 20})
return c.JSONP(data, "customFunc")
// => customFunc({"name": "Grame", "age": 20})
})
Links
在链接后面加上属性,以填充响应的“链接HTTP”标头字段。
app.Get("/", func(c *fiber.Ctx) error {
c.Links(
"http://api.example.com/users?page=2", "next",
"http://api.example.com/users?page=5", "last",
)
// Link: <http://api.example.com/users?page=2>; rel="next",
// <http://api.example.com/users?page=5>; rel="last"
// ...
})
Locals
一种存储范围为请求的变量的方法,该方法仅可用于与请求匹配的路由。(添加上下文件变量,用于内部数据传递?)
app.Use(func(c *fiber.Ctx) error {
c.Locals("user", "admin")
return c.Next()
})
app.Get("/admin", func(c *fiber.Ctx) error {
if c.Locals("user") == "admin" {
return c.Status(200).SendString("Welcome, admin!")
}
return c.SendStatus(403)
})
Location
将响应位置HTTP标头设置为指定的path参数。
app.Post("/", func(c *fiber.Ctx) error {
return c.Location("http://example.com")
return c.Location("/foo/bar")
})
Method
app.Post("/", func(c *fiber.Ctx) error {
c.Method() // "POST"
c.Method("GET")
c.Method() // GET
})
MultipartForm
要访问多部分表单条目,可以使用MultipartForm()解析二进制文件。 这将返回一个map [string] [] string,因此给定一个键,该值将是一个字符串切片。
app.Post("/", func(c *fiber.Ctx) error {
// Parse the multipart form:
if form, err := c.MultipartForm(); err == nil {
// => *multipart.Form
if token := form.Value["token"]; len(token) > 0 {
// Get key value:
fmt.Println(token[0])
}
// Get all files from "documents" key:
files := form.File["documents"]
// => []*multipart.FileHeader
// Loop through files:
for _, file := range files {
fmt.Println(file.Filename, file.Size, file.Header["Content-Type"][0])
// => "tutorial.pdf" 360641 "application/pdf"
// Save the files to disk:
if err := c.SaveFile(file, fmt.Sprintf("./%s", file.Filename)); err != nil {
return err
}
}
}
return err
})
Next
调用Next时,它将在堆栈中执行与当前路由匹配的next方法。 您可以在方法内传递一个错误结构,该结构将结束链接并调用错误处理程序。
app.Get("/", func(c *fiber.Ctx) error {
fmt.Println("1st route!")
return c.Next()
})
app.Get("*", func(c *fiber.Ctx) error {
fmt.Println("2nd route!")
return c.Next()
})
app.Get("/", func(c *fiber.Ctx) error {
fmt.Println("3rd route!")
return c.SendString("Hello, World!")
})
OriginalURL
返回原始请求URL。
// GET http://example.com/search?q=something
app.Get("/", func(c *fiber.Ctx) error {
c.OriginalURL() // "/search?q=something"
// ...
})
Params
// GET http://example.com/user/fenny
app.Get("/user/:name", func(c *fiber.Ctx) error {
c.Params("name") // "fenny"
// ...
})
// GET http://example.com/user/fenny/123
app.Get("/user/*", func(c *fiber.Ctx) error {
c.Params("*") // "fenny/123"
c.Params("*1") // "fenny/123"
// ...
})
路由中的字符和计数器可以获取未命名的路由参数(*,+)
// ROUTE: /v1/*/shop/*
// GET: /v1/brand/4/shop/blue/xs
c.Params("*1") // "brand/4"
c.Params("*2") // "blue/xs"
出于向下兼容性的原因,也可以在没有计数器的情况下访问参数字符的第一个参数段。
app.Get("/v1/*/shop/*", func(c *fiber.Ctx) error {
c.Params("*") // outputs the values of the first wildcard segment
})
ParamsInt
方法可用于从路由参数获取整数。 请注意,如果该参数不在请求中,则将返回零。 如果参数不是数字,则为零,并且将返回错误
// GET http://example.com/user/123
app.Get("/user/:name", func(c *fiber.Ctx) error {
id, err := c.ParamsInt("id") // int 123 and no error
// ...
})
Path
返回请求中的路径部份
// GET http://example.com/users?sort=desc
app.Get("/users", func(c *fiber.Ctx) error {
c.Path() // "/users"
c.Path("/john")
c.Path() // "/john"
// ...
})
Protocol
// GET http://example.com
app.Get("/", func(c *fiber.Ctx) error {
c.Protocol() // "http"
})
Query
// GET http://example.com/shoes?order=desc&brand=nike
app.Get("/", func(c *fiber.Ctx) error {
c.Query("order") // "desc"
c.Query("brand") // "nike"
c.Query("empty", "nike") // "nike"
})
QueryParser
此方法类似于BodyParser,但用于查询参数。
// Field names should start with an uppercase letter
type Person struct {
Name string `query:"name"`
Pass string `query:"pass"`
Products []string `query:"products"`
}
app.Get("/", func(c *fiber.Ctx) error {
p := new(Person)
if err := c.QueryParser(p); err != nil {
return err
}
log.Println(p.Name) // john
log.Println(p.Pass) // doe
log.Println(p.Products) // [shoe, hat]
// ...
})
// Run tests with the following curl command
// curl -X POST "http://localhost:3000/?name=john&pass=doe&products=shoe,hat"
Range
将返回一个包含类型和范围片的结构体。
// Range: bytes=500-700, 700-900
app.Get("/", func(c *fiber.Ctx) error {
b := c.Range(1000)
if b.Type == "bytes" {
for r := range r.Ranges {
fmt.Println(r)
// [500, 700]
}
}
})
Redirect
app.Get("/coffee", func(c *fiber.Ctx) error {
return c.Redirect("/teapot")
})
app.Get("/teapot", func(c *fiber.Ctx) error {
return c.Status(fiber.StatusTeapot).Send("🍵 short and stout 🍵")
})
app.Get("/", func(c *fiber.Ctx) error {
return c.Redirect("/foo/bar")
return c.Redirect("../login")
return c.Redirect("http://example.com")
return c.Redirect("http://example.com", 301)
})
Render
使用数据渲染视图并发送text/html响应。 默认情况下,Render使用默认的Go Template引擎。 如果您想使用其他View引擎,请查看我们的模板中间件。
Route
返回匹配的Route结构。
// http://localhost:8080/hello
app.Get("/hello/:name", func(c *fiber.Ctx) error {
r := c.Route()
fmt.Println(r.Method, r.Path, r.Params, r.Handlers)
// GET /hello/:name handler [name]
// ...
})
SaveFile
方法用于将任何multipart文件保存到磁盘。
app.Post("/", func(c *fiber.Ctx) error {
// Parse the multipart form:
if form, err := c.MultipartForm(); err == nil {
// => *multipart.Form
// Get all files from "documents" key:
files := form.File["documents"]
// => []*multipart.FileHeader
// Loop through files:
for _, file := range files {
fmt.Println(file.Filename, file.Size, file.Header["Content-Type"][0])
// => "tutorial.pdf" 360641 "application/pdf"
// Save the files to disk:
if err := c.SaveFile(file, fmt.Sprintf("./%s", file.Filename)); err != nil {
return err
}
}
return err
}
})
Secure
如果建立了TLS连接,则为true的布尔属性。
Send
设置HTTP响应主体。
app.Get("/", func(c *fiber.Ctx) error {
return c.Send([]byte("Hello, World!")) // => "Hello, World!"
})
app.Get("/", func(c *fiber.Ctx) error {
return c.SendString("Hello, World!")
// => "Hello, World!"
return c.SendStream(bytes.NewReader([]byte("Hello, World!")))
// => "Hello, World!"
})
SendFile
从给定路径传输文件。基于文件名扩展名设置Content-Type响应HTTP报头字段。
app.Get("/not-found", func(c *fiber.Ctx) error {
return c.SendFile("./public/404.html");
// Disable compression
return c.SendFile("./static/index.html", false);
})
SendStatus
app.Get("/not-found", func(c *fiber.Ctx) error {
return c.SendStatus(415)
// => 415 "Unsupported Media Type"
c.SendString("Hello, World!")
return c.SendStatus(415)
// => 415 "Hello, World!"
})
Set
将响应的HTTP报头字段设置为指定的键值。
app.Get("/", func(c *fiber.Ctx) error {
c.Set("Content-Type", "text/plain")
// => "Content-type: text/plain"
})
Status
app.Get("/", func(c *fiber.Ctx) error {
c.Status(200)
return nil
return c.Status(400).Send("Bad Request")
return c.Status(404).SendFile("./public/gopher.png")
})
Subdomains
返回请求域名中的子域的字符串片段。
应用程序属性子域偏移量(默认为2)用于确定子域段的开头。
// Host: "tobi.ferrets.example.com"
app.Get("/", func(c *fiber.Ctx) error {
c.Subdomains() // ["ferrets", "tobi"]
c.Subdomains(1) // ["tobi"]
})
Type
将Content-Type HTTP标头设置为文件扩展名在此处列出的MIME类型。
app.Get("/", func(c *fiber.Ctx) error {
c.Type(".html") // => "text/html"
c.Type("html") // => "text/html"
c.Type("png") // => "image/png"
c.Type("json", "utf-8") // => "application/json; charset=utf-8"
})
Vary
将给定的报头字段添加到Vary响应报头。这将附加标题(如果还没有列出),否则将其留在当前位置。
app.Get("/", func(c *fiber.Ctx) error {
c.Vary("Origin") // => Vary: Origin
c.Vary("User-Agent") // => Vary: Origin, User-Agent
// No duplicates
c.Vary("Origin") // => Vary: Origin, User-Agent
c.Vary("Accept-Encoding", "Accept")
// => Vary: Origin, User-Agent, Accept-Encoding, Accept
// ...
})
Write
app.Get("/", func(c *fiber.Ctx) error {
c.Write([]byte("Hello, World!")) // => "Hello, World!"
fmt.Fprintf(c, "%s\n", "Hello, World!") // "Hello, World!Hello, World!"
})
XHR
如果请求的X-Requested-With报头字段是XMLHttpRequest,这是一个布尔属性,表示请求是由客户端库(如jQuery)发出的。
// X-Requested-With: XMLHttpRequest
app.Get("/", func(c *fiber.Ctx) error {
c.XHR() // true
// ...
})
中间件
BasicAuth
Fiber的基本身份验证中间件,提供HTTP基本身份验证。 它为有效凭据调用下一个处理程序,为缺少或无效的凭据调用401未经授权或自定义响应。
import (
"github.com/gofiber/fiber/v2"
"github.com/gofiber/fiber/v2/middleware/basicauth"
)
// 提供最少的配置
// 将弹出授权框,输入帐号密码
app.Use(basicauth.New(basicauth.Config{
Users: map[string]string{
"john": "doe",
"admin": "123456",
},
}))
// 或者扩展您的配置进行自定义
app.Use(basicauth.New(basicauth.Config{
Users: map[string]string{
"john": "doe",
"admin": "123456",
},
Realm: "Forbidden",
Authorizer: func(user, pass string) bool {
if user == "john" && pass == "doe" {
return true
}
if user == "admin" && pass == "123456" {
return true
}
return false
},
Unauthorized: func(c *fiber.Ctx) error {
return c.SendFile("./unauthorized.html")
},
ContextUsername: "_user",
ContextPassword: "_pass",
}))
Cache
用于Fiber的缓存中间件,旨在拦截响应并进行缓存。 该中间件将使用c.Path()作为唯一标识符来缓存主体,内容类型和状态代码。
import (
"github.com/gofiber/fiber/v2"
"github.com/gofiber/fiber/v2/middleware/cache"
)
// 初始化默认配置
app.Use(cache.New())
// 或者扩展您的配置进行自定义
app.Use(cache.New(cache.Config{
Next: func(c *fiber.Ctx) bool {
return c.Query("refresh") == "true"
},
Expiration: 30 * time.Minute,
CacheControl: true, // 启用客户端缓存
}))
// 缺省配置
var ConfigDefault = Config{
Next: nil,
Expiration: 1 * time.Minute,
CacheControl: false,
KeyGenerator: func(c *fiber.Ctx) string { // 让您生成自定义密钥,默认情况下使用c.Path()
return c.Path()
},
Storage: nil, // 用于存储中间件的状态
}
Compress
用于Fiber的压缩中间件,它将根据Accept-Encoding标头使用gzip,deflate和brotli压缩来压缩响应。
// Default: LevelDefault
// LevelDisabled: -1
// LevelDefault: 0
// LevelBestSpeed: 1
// LevelBestCompression: 2
// 缺省配置
app.Use(compress.New())
// 提供一个自定义压缩级别
app.Use(compress.New(compress.Config{
Level: compress.LevelBestSpeed, // 1
}))
// 跳过特定路由的中间件
app.Use(compress.New(compress.Config{
Next: func(c *fiber.Ctx) bool {
return c.Path() == "/dont_compress"
},
Level: compress.LevelBestSpeed, // 1
}))
CORS
用于通过各种选项启用跨域资源共享。
// 缺省配置
app.Use(cors.New())
// 或者扩展您的配置进行自定义
app.Use(cors.New(cors.Config{
AllowOrigins: "https://gofiber.io, https://gofiber.net",
AllowHeaders: "Origin, Content-Type, Accept",
}))
// 缺省配置
var ConfigDefault = Config{
Next: nil,
AllowOrigins: "*", // 可以访问该资源的源列表。
AllowMethods: "GET,POST,HEAD,PUT,DELETE,PATCH", // 访问资源时允许的列表方法。
AllowHeaders: "", // 请求头列表,当提出实际请求
AllowCredentials: false, // 是否响应请求
ExposeHeaders: "", // 允许客户端访问的白名单
MaxAge: 0,
}
CSRF
通过cookie传递csrf令牌来提供跨站点请求伪造保护。
// Initialize default config
app.Use(csrf.New())
// Or extend your config for customization
app.Use(csrf.New(csrf.Config{
KeyLookup: "header:X-Csrf-Token",
CookieName: "csrf_",
CookieSameSite: "Strict",
Expiration: 1 * time.Hour,
KeyGenerator: utils.UUID,
}))
ETag
使缓存更高效并节省带宽,因为如果内容未更改,则Web服务器不需要重新发送完整的响应。
// Default middleware config
app.Use(etag.New())
// Get / receives Etag: "13-1831710635" in response header
app.Get("/", func(c *fiber.Ctx) error {
return c.SendString("Hello, World!")
})
var ConfigDefault = Config{
Next: nil,
Weak: false, // 表示使用了弱验证程序。
}
Favicon
可忽略favicon请求或将提供的图标缓存在内存中,以通过跳过磁盘访问来提高性能。 用户代理经常且不加区分地请求favicon.ico,因此,您可能希望通过在记录器中间件之前使用此中间件,将这些请求从日志中排除。
// Provide a minimal config
app.Use(favicon.New())
// Or extend your config for customization
app.Use(favicon.New(favicon.Config{
File: "./favicon.ico",
}))
FileSystem
使您能够从目录提供文件。
// Provide a minimal config
app.Use(filesystem.New(filesystem.Config{
Root: http.Dir("./assets")
}))
// Or extend your config for customization
app.Use(filesystem.New(filesystem.Config{
Root: http.Dir("./assets"),
Browse: true,
Index: "index.html",
NotFoundFile: "404.html",
MaxAge: 3600,
}))
一不小心实现了个静态服务器
package main
import (
"net/http"
"github.com/gofiber/fiber/v2"
"github.com/gofiber/fiber/v2/middleware/filesystem"
)
func main() {
app := fiber.New()
app.Use(filesystem.New(filesystem.Config{
Root: http.Dir("./public"),
}))
app.Listen(":3000")
}
Limiter
Fiber的限制器中间件,用于将重复请求限制为公共API和/或端点(例如密码重置等)。对于API客户端,Web爬网或其他需要限制的任务也很有用。
// Default middleware config
app.Use(limiter.New())
// Or extend your config for customization
app.Use(limiter.New(limiter.Config{
Next: func(c *fiber.Ctx) bool {
return c.IP() == "127.0.0.1"
},
Max: 20,
Expiration: 30 * time.Second,
KeyGenerator: func(c *fiber.Ctx) string {
return c.Get("x-forwarded-for")
},
LimitReached: func(c *fiber.Ctx) error {
return c.SendFile("./toofast.html")
},
Store: myCustomStore{}
}))
type Config struct {
// Next定义一个函数,当返回true时将跳过此中间件。
// Optional. Default: nil
Next func(c *fiber.Ctx) bool
// 发送429响应之前,在“持续时间”秒内最近连接的最大数量
// Default: 5
Max int
// KeyGenerator允许您生成自定义密钥,默认情况下使用c.IP()
// Default: func(c *fiber.Ctx) string {
// return c.IP()
// }
KeyGenerator func(*fiber.Ctx) string
// 过期时间是指在内存中保存请求记录的时间
// Default: 1 * time.Minute
Expiration time.Duration
// 当请求达到限制时调用LimitReached
// Default: func(c *fiber.Ctx) error {
// return c.SendStatus(fiber.StatusTooManyRequests)
// }
LimitReached fiber.Handler
// Store用于存储中间件的状态
// Default: 仅用于此过程的内存存储区
Storage fiber.Storage
}
Logger
用于记录HTTP请求/响应详细信息。
app.Use(logger.New())
app.Use(requestid.New())
app.Use(logger.New(logger.Config{
// For more options, see the Config section
Format: "${pid} ${locals:requestid} ${status} - ${method} ${path}\n",
}))
app.Use(logger.New(logger.Config{
Format: "${pid} ${status} - ${method} ${path}\n",
TimeFormat: "02-Jan-2006",
TimeZone: "America/New_York",
}))
file, err := os.OpenFile("./123.log", os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
if err != nil {
log.Fatalf("error opening file: %v", err)
}
defer file.Close()
app.Use(logger.New(logger.Config{
Output: file,
}))
(为什么没有屏幕显示呢?)
Pprof
通过其HTTP服务器运行时性能分析数据提供pprof可视化工具所需的格式。 通常仅出于注册其HTTP处理程序的副作用而导入该软件包。 处理的路径均以/ debug / pprof /开头。
app.Use(pprof.New())
Recover
用于Fiber的恢复中间件,可以从堆栈链中的任何地方的恐慌中恢复,并将控制处理到集中式的ErrorHandler。
// Default middleware config
app.Use(recover.New())
// This panic will be catch by the middleware
app.Get("/", func(c *fiber.Ctx) error {
panic("I'm an error")
})
Proxy
将请求代理到多个服务器。
// Forward to url
app.Get("/gif", proxy.Forward("https://i.imgur.com/IWaBepg.gif"))
// Make request within handler
app.Get("/:id", func(c *fiber.Ctx) error {
url := "https://i.imgur.com/"+c.Params("id")+".gif"
if err := proxy.Do(c, url); err != nil {
return err
}
// Remove Server header from response
c.Response().Header.Del(fiber.HeaderServer)
return nil
})
// Minimal round robin balancer
app.Use(proxy.Balancer(proxy.Config{
Servers: []string{
"http://localhost:3001",
"http://localhost:3002",
"http://localhost:3003",
},
}))
// Or extend your balancer for customization
app.Use(proxy.Balancer(proxy.Config{
Servers: []string{
"http://localhost:3001",
"http://localhost:3002",
"http://localhost:3003",
},
ModifyRequest: func(c *fiber.Ctx) error {
c.Request().Header.Add("X-Real-IP", c.IP())
return nil
},
ModifyResponse: func(c *fiber.Ctx) error {
c.Response().Header.Del(fiber.HeaderServer)
return nil
},
}))
RequestID
Fiber的RequestID中间件,它在响应中添加一个标识符。
// Default middleware config
app.Use(requestid.New())
// Or extend your config for customization
app.Use(requestid.New(requestid.Config{
Header: "X-Custom-Header",
Generator: func() string {
return "static-id"
},
}))
Session
// Default middleware config
store := session.New()
// This panic will be catch by the middleware
app.Get("/", func(c *fiber.Ctx) error {
// get session from storage
sess, err := store.Get(c)
if err != nil {
panic(err)
}
// save session
defer sess.Save()
// Get value
name := sess.Get("name")
// Set key/value
sess.Set("name", "john")
// Delete key
sess.Delete("name")
// Destroy session
if err := sess.Destroy(); err != nil {
panic(err)
}
return c.SendString(fmt.Sprintf("Welcome %v", name))
})
Timeout
Fiber的超时中间件包装具有超时的fiber.Handler。 如果处理程序花费的时间超过给定的持续时间,则会设置超时错误并将其转发到集中式ErrorHandler。
handler := func(ctx *fiber.Ctx) {
ctx.Send("Hello, World 👋!")
}
app.Get("/foo", timeout.New(handler, 5 * time.Second))
Client
客户端结构代表 Fiber HTTP客户端。
// Client http methods
func (c *Client) Get(url string) *Agent
func (c *Client) Head(url string) *Agent
func (c *Client) Post(url string) *Agent
func (c *Client) Put(url string) *Agent
func (c *Client) Patch(url string) *Agent
func (c *Client) Delete(url string) *Agent
Agent
Agent是建立在fastthttp的HostClient之上的,HostClient有很多方便的助手方法,比如请求方法的专用方法。
a := AcquireAgent()
req := a.Request()
req.Header.SetMethod(MethodGet)
req.SetRequestURI("http://example.com")
if err := a.Parse(); err != nil {
panic(err)
}
code, body, errs := a.Bytes() // ...
UserAgent
agent.UserAgent("fiber")
// ...
Cookie
agent.Cookie("k", "v")
agent.Cookies("k1", "v1", "k2", "v2")
// ...
Referer
agent.Referer("https://docs.gofiber.io")
ContentType
agent.ContentType("custom-type")
Set
agent.Set("k1", "v1").
SetBytesK([]byte("k1"), "v1").
SetBytesV("k1", []byte("v1")).
SetBytesKV([]byte("k2"), []byte("v2"))
// ...
Add
agent.Add("k1", "v1").
AddBytesK([]byte("k1"), "v1").
AddBytesV("k1", []byte("v1")).
AddBytesKV([]byte("k2"), []byte("v2"))
// Headers:
// K1: v1
// K1: v1
// K1: v1
// K2: v2
ConnectionClose
agent.ConnectionClose()
Host
agent.Host("example.com")
QueryString
agent.QueryString("foo=bar")
BasicAuth
agent.BasicAuth("foo", "bar")
Body
agent.BodyString("foo=bar")
agent.Body([]byte("bar=baz"))
agent.BodyStream(strings.NewReader("body=stream"), -1)
// ...
JSON
agent.JSON(fiber.Map{"success": true})
// ...
XML
agent.XML(fiber.Map{"success": true})
Form
args := AcquireArgs()
args.Set("foo", "bar")
agent.Form(args)
// ...
ReleaseArgs(args)
MultipartForm
args := AcquireArgs()
args.Set("foo", "bar")
agent.MultipartForm(args)
// ...
ReleaseArgs(args)
Boundary
设置多部分表单请求的边界。
agent.Boundary("myBoundary")
.MultipartForm(nil)
// ...
SendFile(s)
SendFile读取一个文件并将其附加到一个多部分表单请求中。Sendfiles可以用于附加多个文件。
agent.SendFile("f", "field name")
.SendFiles("f1", "field name1", "f2").
.MultipartForm(nil)
// ...
FileData
ff1 := &FormFile{"filename1", "field name1", []byte("content")}
ff2 := &FormFile{"filename2", "field name2", []byte("content")}
agent.FileData(ff1, ff2).
MultipartForm(nil)
// ...
Debug
调试模式启用将请求和响应详细信息记录到io.writer(默认为os.Stdout)。
agent.Debug()
Timeout
agent.Timeout(time.Second)
Reuse
允许一个请求后再次使用代理实例。 如果代理是可重用的,那么当不再使用它时,应该手动释放它。
agent.Reuse()
InsecureSkipVerify
InsecureSkipVerify控制Agent是否验证服务器证书链和主机名。
agent.InsecureSkipVerify()
TLSConfig
// Create tls certificate
cer, _ := tls.LoadX509KeyPair("pem", "key")
config := &tls.Config{
Certificates: []tls.Certificate{cer},
}
agent.TLSConfig(config)
// ...
MaxRedirectsCount
MaxRedirectsCount设置GET和HEAD的最大重定向计数。
agent.MaxRedirectsCount(7)
JSONEncoder
JSONEncoder设置自定义json编码器
agent.JSONEncoder(json.Marshal)
JSONDecoder
JSONDecoder设置自定义json解码器
agent.JSONDecoder(json.Unmarshal)
Request
req := agent.Request()
SetResponse
resp := AcquireResponse()
agent.SetResponse(resp)
// ...
ReleaseResponse(resp)
Dest
目的地设置自定义目标。 dest的内容将由响应主体替换,如果dest太小,将分配新的切片。
agent.Dest(nil)
Bytes
code, body, errs := agent.Bytes()
String
code, body, errs := agent.String()
Struct
var d data
code, body, errs := agent.Struct(&d)
路由
路径
// 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")
})
参数
// 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")
})
// http://localhost:3000/plantae/prunus.persica
app.Get("/plantae/:genus.:species", func(c *fiber.Ctx) error {
fmt.Fprintf(c, "%s.%s\n", c.Params("genus"), c.Params("species"))
return nil // prunus.persica
})
// 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
})
// http://localhost:3000/shop/product/color:blue/size:xs
app.Get("/shop/product/color::color/size::size", func(c *fiber.Ctx) error {
fmt.Fprintf(c, "%s:%s\n", c.Params("color"), c.Params("size"))
return nil // blue:xs
})
// 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)
中间件
app.Use(func(c *fiber.Ctx) error {
// Set some security headers:
c.Set("X-XSS-Protection", "1; mode=block")
c.Set("X-Content-Type-Options", "nosniff")
c.Set("X-Download-Options", "noopen")
c.Set("Strict-Transport-Security", "max-age=5184000")
c.Set("X-Frame-Options", "SAMEORIGIN")
c.Set("X-DNS-Prefetch-Control", "off")
// Go to next middleware:
return c.Next()
})
app.Get("/", func(c *fiber.Ctx) error {
return c.SendString("Hello, World!")
})
分组
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"))
}
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"))
}
组处理程序
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"))
}
模板
// Pass engine to Fiber's Views Engine
app := fiber.New(fiber.Config{
Views: engine,
})
app.Get("/", func(c *fiber.Ctx) error {
return c.Render("index", fiber.Map{
"hello": "world",
});
})
引擎
为多个模板引擎提供包装器: html、ace、amber、django、handlebars、jet、mustache、pug
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")
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"))
}
错误句柄
Fiber通过将错误返回到处理程序来支持集中式错误处理,该处理程序使您可以将错误记录到外部服务或向客户端发送自定义的HTTP响应。
捕捉错误
确保Fiber捕获运行路由处理程序和中间件时发生的所有错误至关重要。 您必须将它们返回到处理程序函数,Fiber将在其中处理并处理它们。
app.Get("/", func(c *fiber.Ctx) error {
// Pass error to Fiber
return c.SendFile("file-does-not-exist")
})
默认情况下不处理紧急情况。 要从堆栈中的任何处理程序引发的恐慌中恢复,您需要在下面包括“Recover间件”:
package main
import (
"github.com/gofiber/fiber/v2"
"github.com/gofiber/fiber/v2/middleware/recover"
)
func main() {
app := fiber.New()
app.Use(recover.New())
app.Get("/", func(c *fiber.Ctx) error {
panic("This panic is catched by fiber")
})
log.Fatal(app.Listen(":3000"))
}
您可以使用Fiber的自定义错误结构来使用Fiber . newerror()传递额外的状态代码。传递消息是可选的;如果为空,则默认为状态代码消息(404 = Not Found)。
app.Get("/", func(c *fiber.Ctx) error {
// 503 Service Unavailable
return fiber.ErrServiceUnavailable
// 503 On vacation!
return fiber.NewError(fiber.StatusServiceUnavailable, "On vacation!")
})
默认的错误处理程序
// Default error handler
var DefaultErrorHandler = func(c *fiber.Ctx, err error) error {
// Default 500 statuscode
code := fiber.StatusInternalServerError
if e, ok := err.(*fiber.Error); ok {
// Override status code if fiber.Error type
code = e.Code
}
// Set Content-Type: text/plain; charset=utf-8
c.Set(fiber.HeaderContentType, fiber.MIMETextPlainCharsetUTF8)
// Return statuscode with error message
return c.Status(code).SendString(err.Error())
}
自定义错误处理程序
// Create a new fiber instance with custom config
app := fiber.New(fiber.Config{
// Override default error handler
ErrorHandler: func(ctx *fiber.Ctx, err error) error {
// Statuscode defaults to 500
code := fiber.StatusInternalServerError
// Retreive the custom statuscode if it's an fiber.*Error
if e, ok := err.(*fiber.Error); ok {
code = e.Code
}
// Send custom error page
err = ctx.Status(code).SendFile(fmt.Sprintf("./%d.html", code))
if err != nil {
// In case the SendFile fails
return ctx.Status(500).SendString("Internal Server Error")
}
// Return from handler
return nil
},
})
// ...
Validation
Fiber可以充分利用验证程序包,以确保正确验证要存储的数据。
type Job struct{
Type string `validate:"required,min=3,max=32"`
Salary int `validate:"required,number"`
}
type User struct{
Name string `validate:"required,min=3,max=32"`
IsActive bool `validate:"required,eq=True|eq=False"`
Email string `validate:"required,email,min=6,max=32"`
Job Job `validate:"dive"`
}
type ErrorResponse struct {
FailedField string
Tag string
Value string
}
func ValidateStruct(user User) []*ErrorResponse {
var errors []*ErrorResponse
validate := validator.New()
err := validate.Struct(user)
if err != nil {
for _, err := range err.(validator.ValidationErrors) {
var element ErrorResponse
element.FailedField = err.StructNamespace()
element.Tag = err.Tag()
element.Value = err.Param()
errors = append(errors, &element)
}
}
return errors
}
func AddUser(c *fiber.Ctx) {
//Connect to database
user := new(User)
if err := c.BodyParser(user); err != nil {
c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
message: err.Error(),
})
return
}
errors := ValidateStruct(*user)
if errors != nil {
c.JSON(errors)
return
}
//Do something else here
//Return user
c.JSON(user)
}
// Running a test with the following curl commands
// curl -X POST -H "Content-Type: application/json" --data "{\"name\":\"john\",\"isactive\":\"True\"}" http://localhost:8080/register/user
// Results in
// [{"FailedField":"User.Email","Tag":"required","Value":""},{"FailedField":"User.Job.Salary","Tag":"required","Value":""},{"FailedField":"User.Job.Type","Tag":"required","Value":""}]
问题/处理
响应404
用一个中间件来处理
app.Use(func(c *fiber.Ctx) error {
return c.Status(fiber.StatusNotFound).SendString("Sorry can't find that!")
})
如何设置错误处理程序?
要覆盖默认错误处理程序,可以在初始化新的Fiber实例时提供Config时覆盖默认。
app := fiber.New(fiber.Config{
ErrorHandler: func(c *fiber.Ctx, err error) error {
return c.Status(500).SendString(err.Error())
},
})
Fiber支持哪些模板引擎?
Ace Amber Django Handlebars HTML Jet Mustache Pug
终于抄完了,再看看示例。我就喜欢这种示例多的。