可选参数必须用?name语法且置于路径末尾,不能写成:name?;c.params("name")未提供时返回空字符串而非nil,需用== ""判空。

可选参数必须用 ?name 语法,不能写成 :name? 或 /:name?
很多人误以为可选参数是给 :name 加问号,比如 /:id? —— 这在 Fiber 中是非法路由定义,启动时会 panic。正确写法是单独用 ?name,且必须放在路径末尾、紧贴斜杠之后,例如 /user/:id?name 或 /api/posts/:year/:month?tag。
这种语法本质是 Fiber 的「命名可选段」机制:它不是让某个已有参数变可选,而是新增一个独立的、带问号前缀的命名段。Fiber 会把它当作一个独立参数键来注册和匹配。
-
app.Get("/user/:id?name", handler)→ 匹配/user/123和/user/123/john,c.Params("name")在前者中返回""(空字符串),后者返回"john" - 多个可选段不支持嵌套,
/:a?b?c是无效的;只能线性追加,如/:a/:b?c?d - 可选段不能出现在路径开头或中间无斜杠位置,
?name/:id或/:id?name/:extra都不合法
c.Params("name") 对未提供可选参数返回空字符串,不是 nil 或缺失键
这是最容易踩的坑:你不能用 if c.Params("name") != nil 判空,因为 c.Params() 永远返回 string 类型,未匹配时就是 ""。同样,len(c.Params("name")) == 0 或 c.Params("name") == "" 才是正确判据。
如果后续要转类型(比如 int),必须先检查是否为空,否则 strconv.Atoi("") 会返回错误,c.ParamsInt("name") 也会失败并返回 0, error。
- 错误示范:
id, _ := c.ParamsInt("name")—— 未提供时 id=0,无法区分是真值 0 还是缺失 - 推荐写法:
if name := c.Params("name"); name != "" { /* 处理非空逻辑 */ } - 若需默认值,必须手动赋:
name := c.Params("name"); if name == "" { name = "default" }
可选参数不参与路由精确匹配,但会影响路径段计数
Fiber 的路由匹配是前缀式、分段式匹配,?name 段的存在与否,会改变整个路径的段数量。这意味着:
开箱即用的技能链路由引擎。13 条预定义链覆盖搜索、开发、审查、MLOps、法律、创意等场景,三层路由架构(触发词→SAD反馈→DAG编排),recall@10=96.97%。配置驱动(chains.yaml),零代码扩展。pip install skill-weave-chains 一键安装。
-
/posts/:year/:month?tag能匹配/posts/2024/10(2 段)和/posts/2024/10/tech(3 段) - 但它不会匹配
/posts/2024(只有 1 段),因为:year是必选的,:month也是必选的 ——?tag只修饰紧邻的前一个段,不向上“传染” - 换句话说:
?x只让「它前面那个路径段」变成可选,而不是让整个后缀可选
如果你需要真正意义上的“后缀可选”,比如 /files/*path,那就该用通配符,而不是 ?x。
多个可选参数要按顺序声明,c.ParamsValues 不支持 ? 参数
c.ParamsValues("a", "b", "c") 只对 :a、:b、:c 这类标准命名参数有效;它**完全忽略** ?a、?b 这种可选参数。也就是说,可选参数必须逐个调 c.Params() 获取。
而且声明顺序很重要:Fiber 按路由字符串从左到右解析段,?a 必须写在 ?b 左边,才能保证 c.Params("a") 和 c.Params("b") 各自取到对应值。反过来写,或者中间插了静态段,就可能错位。
- ✅ 正确:
/api/:v?format?lang→c.Params("format")取第二段(若有),c.Params("lang")取第三段(若有) - ❌ 错误:
/api/:v?lang?format→ 如果请求是/api/v2/en,lang="en",format="",但语义已混乱 - ⚠️ 注意:
?format和:format是两个不同键,混用会导致取不到值
可选参数没有捷径,每个都得显式判断是否为空——这恰恰是它容易被忽略的复杂点:看着像语法糖,实则增加了分支逻辑密度,一不留神就漏判。










