(摘) Fiber 又一个Golang框架

声明:内容源自网络,版权归原作者所有。若有侵权请联系我们

Fiber 是一个受 Express 启发的 web 框架,构建在 Go 最快的 HTTP 引擎 Fasthttp 上。旨在 为 快速 开发提供方便,同时考虑 零内存分配 和 性能。

官网

文档

github

示例

路由

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",
    })

    // ...
})
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})
})

在链接后面加上属性,以填充响应的“链接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")
// ...
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

终于抄完了,再看看示例。我就喜欢这种示例多的。