兜底路由必须用{*path}且星号紧贴左大括号,仅此一种合法写法;须注册在所有具体路由之后,用app.Any覆盖全部HTTP方法,路径参数已解码但双重编码需手动url.PathUnescape处理。

兜底路由必须用 {*path},且星号紧贴左大括号
任意路径匹配只有一种合法写法:{*path}。写成 {*}、{*path }(带空格)、/catchall/* 或 /api/{*p}(非末尾)都会失败或不生效。它匹配从注册位置起的全部剩余路径段,包括斜杠 —— 例如 app.Get("/static/{*file}", h) 中,请求 /static/css/app.css 时,file 值为 css/app.css,不是 app.css。
常见错误:把 {*path} 放在所有路由前面,导致其他路由永远不被命中。必须确保它注册在最后:
- 先注册明确路径:
app.Get("/health", healthHandler) - 再注册带约束的泛化路径:
app.Get("/admin/{*sub}", adminHandler) - 最后注册根级兜底:
app.Any("/{*path}", fallbackHandler)
app.Any 比 app.Get 更适合作为兜底路由
用户可能用任意 HTTP 方法访问不存在路径,只注册 app.Get("/{*path}", ...) 会漏掉 POST /xxx、DELETE /yyy 等请求,返回 405 Method Not Allowed 而非 404。正确做法是用 app.Any 覆盖全部方法:
app.Any("/{*path}", func(ctx iris.Context) { ctx.StatusCode(404); ctx.WriteString("Not found") })
注意:app.Any 不自动继承全局中间件(如 CORS、JWT),需手动挂载或确认中间件作用域已覆盖该路由。
路径参数必须用 ctx.Params().Get,不能用 ctx.URLParam
ctx.URLParam("id") 只读取查询参数(如 ?id=123),而 RESTful 路径中 /user/{id:uint64} 的 id 是路径参数,必须用 ctx.Params().Get("id") 获取。参数名大小写敏感:/user/{ID:uint64} 就得用 ctx.Params().Get("ID"),写成 "id" 返回空字符串。
开箱即用的技能链路由引擎。13 条预定义链覆盖搜索、开发、审查、MLOps、法律、创意等场景,三层路由架构(触发词→SAD反馈→DAG编排),recall@10=96.97%。配置驱动(chains.yaml),零代码扩展。pip install skill-weave-chains 一键安装。
强类型转换要检查错误:
-
id, err := ctx.Params().GetUint64("id")——err != nil必须处理,否则后续 panic - 更稳妥用默认值:
id := ctx.Params().GetIntDefault("id", 0),但语义上要确认 0 是否合理 - 宏类型(如
{id:uint64})在非法值(如/user/abc)时直接 404,不进 handler;写成{id}会导致id恒为 0
动态加载路由必须用 app.Party 分组管理
直接在根 app 上反复调用 app.Get 不是真正动态加载,只是静态注册。运行时增删路由必须基于 Party:
- 创建分组:
group := app.Party("/api/v1") - 向分组注册:
group.Get("/users", usersHandler) - 热更新时调用
group.Reset()清空全部子路由,再重新注册新规则 -
group.Reset()安全,不影响父级路由,也不会引发 GC 泄漏
宏语法(如 {id:int min(1)})必须在注册时完整写死,不能运行时拼接字符串传给 Get —— Iris 的 macro 解析发生在编译阶段,运行时拼接会被当纯字符串处理,ctx.Params().GetIntDefault("id", 0) 将始终返回 0。
容易忽略的是:{*path} 接收的路径已解码,但双重编码(如 %252F 表示 %2F)不会被自动二次解码,需手动调用 url.PathUnescape;另外,{path:path} 类型必须放在路径末尾,且不校验长度或格式,这些都得自己在 handler 里补全。










