🔌 路由
处理程序
注册绑定到特定 HTTP 方法的路由。
// 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
// 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
等
func (app *App) Use(args ...interface{}) Router
// 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()
})
路径
路由路径与请求方法相结合,定义了可以发出请求的端点。路由路径可以是字符串或字符串模式。
基于字符串的路由路径示例
// 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")
})
与 expressJs 框架一样,路由声明的顺序很重要。当收到请求时,会按照声明的顺序检查路由。
因此,请注意将带有可变参数的路由写在包含固定部分的路由之后,以免这些可变部分反而匹配,从而导致意外的行为发生。
参数
路由参数是路由中的动态元素,它们是命名或未命名的片段。这些片段用于捕获在其 URL 位置指定的值。可以使用 Params 函数获取这些值,其中路径中指定的路由参数名称作为其各自的键,或者对于未命名参数,使用字符(*, +)及其计数器。
字符 :, + 和 * 是引入参数的字符。
贪婪参数由通配符(*)或加号(+)表示。
路由还提供了使用可选参数的可能性,对于命名参数,它们以最终的 "?" 标记,与非可选的加号不同,你可以使用通配符来表示可选且贪婪的参数范围。
定义带路由参数的路由示例
// 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")
})
由于连字符 (-
) 和点 (.
) 被字面解释,它们可以与路由参数一起用于有用目的。
所有特殊的参数字符也可以用 "\\"
转义并失去其特殊含义,因此如果你愿意,可以在路由中使用它们,就像 Google API 设计指南中的自定义方法一样。建议使用反引号 `
,因为在 go 的正则表达式文档中,他们总是使用反引号来确保清晰无误,并且转义字符不会以意外方式干扰正则表达式模式。
// 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)
我们已将路由功能高度适配 express 路由,但目前暂不支持正则表达式,因为它们速度较慢。可以在在线 Express 路由测试器中使用 0.1.7 版本 (express 4) 测试其可能性。
约束
路由约束在传入 URL 匹配且 URL 路径由参数分解为路由值时执行。该功能在 v2.37.0
中引入,灵感来自 .NET Core。
约束不是参数的验证。如果约束对参数值无效,Fiber 将返回 404 处理程序。
约束 | 示例 | 示例匹配项 |
---|---|---|
int | :id<int\> | 123456789, -123456789 |
bool | :active<bool\> | true,false |
guid | :id<guid\> | CD2C1638-1638-72D5-1638-DEADBEEF1638 |
float | :weight<float\> | 1.234, -1,001.01e8 |
minLen(值) | :username<minLen(4)\> | Test (必须至少包含 4 个字符) |
maxLen(值) | :filename<maxLen(8)\> | MyFile (必须不超过 8 个字符) |
len(长度) | :filename<len(12)\> | somefile.txt (正好 12 个字符) |
min(值) | :age<min(18)\> | 19 (整数值必须至少为 18) |
max(值) | :age<max(120)\> | 91 (整数值必须不超过 120) |
range(最小值,最大值) | :age<range(18,120)\> | 91 (整数值必须至少为 18 但不超过 120) |
alpha | :name<alpha\> | Rick (字符串必须由一个或多个字母字符组成,不区分大小写) |
datetime | :dob<datetime(2006\\\\-01\\\\-02)\> | 2005-11-01 |
regex(表达式) | :date<regex(\\d{4}-\\d{2}-\\d{2})\> | 2022-08-27 (必须匹配正则表达式) |
示例
- 单约束
- 多约束
- Regex 约束
app.Get("/:test<min(5)>", func(c *fiber.Ctx) error {
return c.SendString(c.Params("test"))
})
// curl -X GET http://localhost:3000/12
// 12
// curl -X GET http://localhost:3000/1
// Cannot GET /1
可以使用 ;
分隔多个约束。
app.Get("/:test<min(100);maxLen(5)>", func(c *fiber.Ctx) error {
return c.SendString(c.Params("test"))
})
// curl -X GET http://localhost:3000/120000
// Cannot GET /120000
// curl -X GET http://localhost:3000/1
// Cannot GET /1
// curl -X GET http://localhost:3000/250
// 250
Fiber 在注册路由时预编译正则表达式查询。因此,regex 约束没有性能开销。
app.Get(`/:date<regex(\d{4}-\d{2}-\d{2})>`, func(c *fiber.Ctx) error {
return c.SendString(c.Params("date"))
})
// curl -X GET http://localhost:3000/125
// Cannot GET /125
// curl -X GET http://localhost:3000/test
// Cannot GET /test
// curl -X GET http://localhost:3000/2022-08-27
// 2022-08-27
在使用 datetime 约束时,应该在路由特定字符 (*
, +
, ?
, :
, /
, <
, >
, ;
, (
, )
) 前使用 \\
,以避免错误的解析。
可选参数示例
你也可以对可选参数施加约束。
app.Get("/:test<int>?", func(c *fiber.Ctx) error {
return c.SendString(c.Params("test"))
})
// curl -X GET http://localhost:3000/42
// 42
// curl -X GET http://localhost:3000/
//
// curl -X GET http://localhost:3000/7.0
// Cannot GET /7.0
中间件
旨在修改请求或响应的函数称为中间件函数。Next 是一个 Fiber 路由器函数,调用时执行匹配当前路由的下一个函数。
中间件函数示例
app.Use(func(c *fiber.Ctx) error {
// Set a custom header on all responses:
c.Set("X-Custom-Header", "Hello, World")
// Go to next middleware:
return c.Next()
})
app.Get("/", func(c *fiber.Ctx) error {
return c.SendString("Hello, World!")
})
Use
方法路径是挂载或前缀路径,它将中间件限制为仅应用于以该路径开头的所有请求路径。
动态添加路由的限制
出于设计和性能方面的考虑,不支持在应用程序启动后动态添加路由。请确保在应用程序启动前定义所有路由。
分组
如果你有许多端点,可以使用 Group
来组织路由。
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"))
}
更多信息请参阅我们的分组指南