Revel路由不支持查询参数占位符,正确写法为GET /company APP.ShowByName;查询参数需用c.Params.Get()获取,路径参数与查询参数必须严格区分。

Revel 路由中不能写 ?key=value 占位符
很多人一上来就想在 conf/routes 里写 GET /company?name:name APP.ShowByName,这会直接导致路由不匹配或 panic。Revel 的路由解析器根本不识别 ? 后面的部分——它只处理路径段(path segment),查询参数(query string)压根不参与路由匹配。
原因很简单:Revel 把所有参数统一收口到 c.Params,设计上就拒绝把 query 参数耦合进路由定义。你加了 ?name:name,框架既不会报错提示,也不会生效,而是静默忽略,最终走到 404 或错误的 action。
- ✅ 正确路由写法:
GET /company APP.ShowByName - ❌ 错误写法:
GET /company?name:name APP.ShowByName、GET /company/:name?category APP.ShowByName - ⚠️ 特别注意:
{id}和:id是路径参数语法,和 query 无关;混用/{id}?q是无效的
c.Params.Get() 是读取 query 参数的唯一推荐方式
只要请求是 GET /company?name=ABC&category=tech,你在控制器里调用 c.Params.Get("name") 就能拿到 "ABC",不需要任何额外绑定或解析。
这是因为 ParamsFilter 在路由匹配后自动执行,把 url.ParseQuery() 的结果、路径变量、表单数据全 merge 进 c.Params(类型是 map[string]string)。它内部用的是 url.Values.Get(),所以对重复 key(如 ?tag=a&tag=b)默认返回第一个值。
- 要取全部值?用
c.Params.Values["tag"],它返回[]string - 要转成 int?别直接
strconv.Atoi(c.Params.Get("id")),先判空再转,否则空字符串 panic - 绑定到结构体?Revel 不提供 query 自动 bind,得手动取 + 转 + 校验
路径参数 {id} 和 query 参数必须区分清楚
比如你要支持两种访问方式:/hotels/123(路径 ID)和 /hotels?city=shanghai(查询条件),它们语义不同,不能混用。
{id} 是 RESTful 资源标识,强制出现在 URL 路径里;query 参数是可选筛选条件,不影响资源定位。Revel 允许你同时用两者,但必须分开处理:
-
GET /hotels/{id} Hotels.Show→c.Params.Get("id")拿路径值("123") -
GET /hotels Hotels.List→c.Params.Get("city")拿查询值("shanghai") - 如果请求是
/hotels/123?format=json,c.Params.Get("id")和c.Params.Get("format")都有效
别试图用正则约束 query 参数,比如 GET /hotels/{city} Hotels.List —— 这匹配的是路径段 /hotels/shanghai,不是 /hotels?city=shanghai。
开发时容易漏掉的兼容性细节
Revel 的 c.Params.Get() 看似简单,但在实际联调中常因环境差异出问题:
- Nginx 反向代理时没传
X-Forwarded-For或X-Forwarded-Proto,会导致某些中间件(如 SessionFilter)误判协议,间接影响参数解析上下文 - 前端用
fetch发 GET 请求但 body 里塞了 JSON?Revel 不会解析 body,c.Params里只有 query 和路径参数,body 内容得自己读c.Request.Body - 测试时用
revel.Test模拟请求,必须显式构造url.Values并设到req.URL.RawQuery,否则c.Params.Get()返回空
最稳妥的做法:所有 query 参数都做非空校验 + 类型转换封装,别信前端传来的任何值。



















