:param 与 *path 的区别与使用注意

结论先行

:name 匹配单个路径段(不含 /);*name(catch-all)匹配剩余的全部路径(含 /),且必须是路由的最后一段。取值统一用 c.Param("name"),catch-all 拿到的值会保留前导斜杠。

对比表

维度:param(参数段)*path(通配段/catch-all)
匹配范围一个段,不含 /剩余全部内容,含 /
示例/user/:id/files/*filepath
请求 /user/123id=“123”不适用
请求 /files/a/b/c不适用filepath=“/a/b/c”
约束段名在同一位置唯一;不与冲突模式共存必须最后一段;同层其他子路由受限
典型用途资源 ID、slug静态文件路径、前端路由回退

使用注意

  • 路径里出现 / 必须用 *path:param 永远截断在下一个 /
  • *filepath 的值带前导 /,做磁盘路径前常用 strings.TrimPrefix 去掉。
  • 路由注册顺序无关紧要,匹配靠树结构而不是“先注册先匹配”。
  • Gin 默认开启尾斜杠自动重定向(RedirectTrailingSlash)与固定路径纠正(RedirectFixedPath 默认关),设计 API 时尽量别依赖 301 纠正。

代码示例

r.GET("/users/:id", func(c *gin.Context) {
    id := c.Param("id") // "/users/123" -> "123"
    c.String(200, id)
})

r.GET("/files/*filepath", func(c *gin.Context) {
    p := c.Param("filepath")      // "/files/a/b.txt" -> "/a/b.txt"
    name := strings.TrimPrefix(p, "/")
    c.String(200, name)
})

常见追问 / 记忆点

  • 追问:/user/:id 和 /user/new 会不会冲突?答:不会冲突且静态段优先命中(/user/new 走 new 的 handler);只有同位置通配符互相冲突才 panic,细节以官方文档为准。
  • 追问:什么时候用 *path?答:需要吞掉“任意多段”时,例如文件下载、SPA history 路由回退(配合 NoRoute 也可)。
  • 记忆点:: 一段,* 到底;* 必须垫底,取值带前导斜杠。
笔记加载中…