路径参数须用:name声明且仅匹配单段,不跨斜杠;需注意编码解码、命名规范、StrictRouting、与查询参数区分、v3约束校验及参数生命周期。

路径参数必须用 :name 形式声明,且只匹配单个路径段,不能跨斜杠
比如 /users/:id 能匹配 /users/123,但不会匹配 /users/123/profile——后者需要额外注册 /users/:id/profile 或改用通配符 /users/:id/*path(注意通配符只能在末尾)。
常见错误是写成 /users/:id/:name 却传入 /users/123/john%20doe,这时 c.Params("name") 拿到的是 "john%20doe",不是解码后的 "john doe",得手动调 url.PathUnescape。
-
:id这类参数名里不能含下划线或大写字母,:user_id或:UserId都不被识别,只认纯小写+字母数字组合 - 同级路径中,
/users/new和/users/:id可共存;但/users/:id和/users/:slug不能共存,后者会覆盖前者 - 参数值默认是字符串,转整型别直接用
strconv.Atoi(c.Params("id")),它会触发内存分配;高频场景建议用fasthttp提供的strconv.ParseUint配合c.Params("id")的底层字节切片(需确保无前导空格)
为什么 c.Params("id") 有时返回空?
不是代码写错了,而是路由根本没匹配上。Fiber 匹配靠基数树,不是正则回溯。如果请求是 /users/123/(结尾有斜杠),而你只注册了 /users/:id,那就会 404——因为 /users/:id 和 /users/:id/ 是两个不同路径。
StrictRouting 默认开启,意味着 /users/123 和 /users/123/ 不互通。解决办法只有两个:
- 显式注册带斜杠版本:
app.Get("/users/:id/", handler) - 加中间件统一重定向:
ctx.Redirect(301, strings.TrimSuffix(ctx.Path(), "/"))
:id 和查询参数 ?id=123 别混用
路径参数 :id 来自 URL 路径段,用 c.Params("id") 取;查询参数 id 来自 ? 后面,用 c.Query("id") 取。两者底层存储、解析时机、缓存行为都不同,强行混用会导致逻辑错乱。
比如你同时有 /posts/:id?draft=true,c.Params("id") 是路径部分,c.Query("draft") 才是查询部分——不要试图用 c.Params("draft") 去取。
另外,c.Query("id", "0") 支持默认值,但 c.Params("id") 不支持,默认就是空字符串,得自己判空。
v3 的自定义约束让校验更干净
Fiber v3 支持 RegisterCustomConstraint,可以给 :id 绑定规则,比如只接受纯数字:
app.RegisterCustomConstraint("id", func(value string) bool {
_, err := strconv.ParseUint(value, 10, 64)
return err == nil
})
app.Get("/users/:id{id}", handler)
这样当请求 /users/abc 时,直接 404,不用在 handler 里做 if 判定。但注意:约束函数运行在匹配阶段,失败不进 handler,也不触发任何中间件。
真正容易被忽略的是参数生命周期——c.Params() 返回的字符串指向 fasthttp 内部缓冲区,handler 返回后就失效。如果你在 goroutine 里异步用它,必须先 string(c.Params("id")) 拷贝一份,否则可能读到脏数据。


















