兜底路由必须用{*path}通配符且星号紧贴左大括号,匹配全部剩余路径段;须注册在所有具体路由之后;应使用app.Any覆盖所有HTTP方法;路径参数已解码,双重编码需手动url.PathUnescape处理。

兜底路由必须用 {*path} 通配符模式
Iris 中没有类似 Express 的 * 或 Gin 的 :path 语法,唯一合法的任意路径匹配写法是 {*path} —— 注意星号必须紧贴左大括号,中间不能有空格,且变量名(如 path)可自定义但必须存在。写成 {*}、{*path } 或 /catchall/* 都会直接报错或无法匹配。
它匹配从当前前缀开始的**全部剩余路径段**,包括斜杠,例如:
-
app.Get("/{*path}", handler)能匹配/a、/a/b/c?x=1、/api/v1/users/123/edit -
app.Get("/static/{*file}", handler)匹配/static/css/app.css,此时file值为css/app.css
必须注册在所有具体路由之后
Iris 按注册顺序匹配端点,{*path} 是最低优先级的模式,一旦它被提前注册,就会拦截掉本该命中更精确路由的请求。比如:
app.Get("/{*path}", fallbackHandler) // ❌ 错误:放太前
app.Get("/health", healthHandler)
app.Get("/api/users", usersHandler)
上面三行中,/health 永远不会被调用,因为 {*path} 先匹配成功。正确顺序是:
开箱即用的技能链路由引擎。13 条预定义链覆盖搜索、开发、审查、MLOps、法律、创意等场景,三层路由架构(触发词→SAD反馈→DAG编排),recall@10=96.97%。配置驱动(chains.yaml),零代码扩展。pip install skill-weave-chains 一键安装。
- 先注册所有明确路径(
/login、/api/{id:int}等) - 再注册带约束的泛化路由(如
/admin/{*subpath}) - 最后注册根级兜底:
app.Any("/{*path}", fallbackHandler)
app.Any 比 app.Get 更适合作为兜底
用户可能输入任意 HTTP 方法访问不存在路径,只用 app.Get("/{*path}", ...) 会漏掉 POST /xxx、DELETE /yyy 这类请求。实际兜底应覆盖全部方法:
app.Any("/{*path}", func(ctx iris.Context) { ctx.StatusCode(404); ctx.WriteString("Not found") })- 若需区分方法再处理,可用
ctx.Method()获取当前动词 - 注意:
app.Any不会自动继承 CORS 或其他全局中间件,需手动挂载或确保中间件作用域覆盖该路由
容易忽略的路径编码与重定向陷阱
{*path} 接收的是**已解码**的路径,但浏览器或代理可能发送双重编码路径(如 %252F 表示 %2F),Iris 默认不二次解码。这会导致 /files/a%2Fb.txt 中的 path 值变成 a%2Fb.txt 而非 a/b.txt。
解决方案只有两个:
- 前端确保只发一次编码的路径
- 后端在 handler 中手动调用
url.PathUnescape(ctx.Params().Get("path"))(需 importnet/url)
另外,不要在兜底路由里直接做 301 重定向到带尾部斜杠的路径——这会和静态文件服务、SPA 的 history fallback 产生冲突,优先用 404 + 统一错误页。


















