🔌 路由
处理程序
注册绑定到特定 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 的正则表达式文档中,它们始终使用反引号以确保明确,并且转义字符不会以意外的方式干扰正则表达式模式。
// https://127.0.0.1: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
})
// https://127.0.0.1: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
})
我们的智能路由器识别出引入参数字符在这种情况下应成为请求路由的一部分,并且可以对其进行处理。
// https://127.0.0.1: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(value) | :username<minLen(4)\> | Test(必须至少包含 4 个字符) |
maxLen(value) | :filename<maxLen(8)\> | MyFile(不得超过 8 个字符) |
len(length) | :filename<len(12)\> | somefile.txt(恰好 12 个字符) |
min(value) | :age<min(18)\> | 19(整数值必须至少为 18) |
max(value) | :age<max(120)\> | 91(整数值不得超过 120) |
range(min,max) | :age<range(18,120)\> | 91(整数值必须至少为 18,但不得超过 120) |
alpha | :name<alpha\> | Rick(字符串必须包含一个或多个字母字符,a-z,且不区分大小写) |
datetime | :dob<datetime(2006\\\\-01\\\\-02)\> | 2005-11-01 |
regex(expression) | :date<regex(\\d{4}-\\d{2}-\\d{2})\> | 2022-08-27(必须匹配正则表达式) |
示例
- 单个约束
- 多个约束
- 正则约束
app.Get("/:test<min(5)>", func(c *fiber.Ctx) error {
return c.SendString(c.Params("test"))
})
// curl -X GET https://127.0.0.1:3000/12
// 12
// curl -X GET https://127.0.0.1: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 https://127.0.0.1:3000/120000
// Cannot GET /120000
// curl -X GET https://127.0.0.1:3000/1
// Cannot GET /1
// curl -X GET https://127.0.0.1:3000/250
// 250
在注册路由时,Fiber 会预编译正则查询。因此,正则约束不会产生性能开销。
app.Get(`/:date<regex(\d{4}-\d{2}-\d{2})>`, func(c *fiber.Ctx) error {
return c.SendString(c.Params("date"))
})
// curl -X GET https://127.0.0.1:3000/125
// Cannot GET /125
// curl -X GET https://127.0.0.1:3000/test
// Cannot GET /test
// curl -X GET https://127.0.0.1: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 https://127.0.0.1:3000/42
// 42
// curl -X GET https://127.0.0.1:3000/
//
// curl -X GET https://127.0.0.1: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"))
}
有关此内容的更多信息,请参阅我们的 分组指南