Revel 路由按约定而非设计,仅解析路径结构,忽略 query 参数;路径变量用 :name,通配符 **filepath 须在末尾;/ 与 /xxx/ 自动归一化匹配同一路由。

Revel 的路由不是“设计出来”的,而是按约定写出来的——写错格式或加查询参数会导致匹配失败,但框架不会报错,只会静默 fallback 到 404 或错误控制器。
路由文件里不能出现 ? 或 =
比如 GET /company?name:string 或 GET /user?id=123 这类写法在 Revel 中完全无效。routes 文件只解析路径结构,? 及之后的内容会被忽略或导致整行路由加载失败,且无明确报错提示。
- ✅ 正确写法:
GET /company APP.ShowByName - ❌ 错误写法:
GET /company?name APP.ShowByName、GET /company/:id?active=true APP.Show - 所有 query 参数(如
?name=ABC&category=tech)都由框架自动注入c.Params,无需、也不能在 routes 中声明
路径参数用 :name 而不是 {name} 或 $name
Revel 使用冒号前缀表示路径变量,例如 /user/:id 中的 :id 会被提取并存入 c.Params.Get("id");它不支持 REST 风格的花括号语法(如 /user/{id}),也不识别美元符($id)。
- 路径参数值默认是
string类型,控制器中可直接用c.Params.Get("id")获取 - 若需强类型绑定(如
int),可在控制器方法签名中声明:func(c App) Show(id int) revel.Result,Revel 会自动调用Params.Bind() -
:id会匹配除/外的任意字符,所以/user/123和/user/abc都能命中 —— 若需校验,得在控制器里手动判断
通配符 *filepath 必须放在路径末尾
静态资源路由 GET /public/*filepath Static.Serve("public") 是唯一允许使用通配符的场景,且 * 必须紧贴路径末尾,中间不能有其他段。
- ✅ 有效:
GET /assets/*filepath Static.Serve("assets") - ❌ 无效:
GET /assets/*filepath/css Static.Serve("assets")(*后不能再跟路径) - 匹配时,
*filepath的值不含开头斜线,例如请求/public/js/app.js→c.Params.Get("filepath") == "js/app.js" - 该参数也进
c.Params,和 query、路径参数一样统一处理
斜线后缀 / 会被自动归一化
Revel 默认把 /hotels 和 /hotels/ 视为同一路径,都会匹配 GET /hotels Hotels.Index。反转路由(如 Hotels.Index.URL())生成的 URL 会带斜线,但不影响匹配逻辑。
- 无法靠有无斜线区分两个路由,
GET /api和GET /api/是同一个入口 - 若需严格区分(极少见),得靠自定义 Filter 拦截并重定向,而不是靠 routes 文件
- 这个行为由
RouterFilter内部的路径规范化逻辑控制,不可关闭
真正容易出问题的地方,是开发者习惯性地把 query 参数写进 routes —— 它不会报错,但你的控制器永远拿不到那个参数,因为路由压根没匹配上,请求直接掉进 fallback 流程。记住:routes 只管「路径怎么走」,不管「参数从哪来」;参数全在 c.Params 里等着你取。



















