必须在注册路由前调用app.onerrorcode,否则404处理器不生效;需用iris.statusnotfound而非字面量404,且泛匹配路由须置于最后以防吞掉未匹配路径。

必须在注册路由前调用 app.OnErrorCode
404 页面不生效,八成是因为 app.OnErrorCode(iris.StatusNotFound, handler) 写在了 app.Get、app.Post 等路由注册之后。Iris 的错误处理器是全局兜底逻辑,一旦常规路由匹配成功(哪怕只是泛匹配如 /user/{id}),就不会再进 404 处理器。所以这行代码必须紧接在 app := iris.New() 或 iris.Default() 之后,且早于任何 app.Handle 调用。
常见错误写法:
app := iris.New()
app.Get("/home", homeHandler)
app.OnErrorCode(iris.StatusNotFound, notFoundHandler) // ❌ 晚了!/abc 会被泛匹配吃掉或直接走默认文本
正确顺序:
app := iris.New()
app.OnErrorCode(iris.StatusNotFound, notFoundHandler) // ✅ 第一行就注册
app.Get("/home", homeHandler)
app.Get("/user/{id:uint64}", userHandler)
渲染模板还是推荐路径?两种 notFoundHandler 写法
选哪种取决于你的场景:品牌展示优先用模板;工具型后台可加路径推荐。
开箱即用的技能链路由引擎。13 条预定义链覆盖搜索、开发、审查、MLOps、法律、创意等场景,三层路由架构(触发词→SAD反馈→DAG编排),recall@10=96.97%。配置驱动(chains.yaml),零代码扩展。pip install skill-weave-chains 一键安装。
- 纯模板渲染:确保
views/errors/404.html存在,函数里直接ctx.View("errors/404.html"),不用手动设状态码——ctx.View内部会自动设为 404 - 动态推荐路径:调用
ctx.FindClosest(3)获取最多 3 个相似路径,但必须检查返回切片长度:if len(closest) == 0 { ctx.StatusCode(404); ctx.WriteString("Page not found"); return },否则空切片会导致页面空白 - 注意:
ctx.FindClosest只比对路径字符串,不区分GET/POST,所以POST /api/login可能被推荐给访问GET /api/logi的用户
为什么访问 /xxx 还是看到默认纯文本?
除了注册时机错,还有三个高频原因:
-
app.OnErrorCode传的是404字面量而非iris.StatusNotFound—— 后者才是框架定义的常量,类型和值都需严格匹配 - 你用了
app.StaticWeb("/static", "./public")之类静态服务,但请求路径如/static/missing.css实际文件不存在,此时 Iris 不触发 404 处理器,而是由FileServer自己返回 404 文本;这种情况下要单独处理静态资源缺失,比如用中间件拦截/static/**并重定向到自定义页 - 开发时用
go run main.go,但模板路径写死相对路径"./views",而工作目录不是项目根;建议统一用os.Executable()构建绝对路径,避免部署后模板找不到
别忽略日志和测试验证
上线前务必手动验证,光看浏览器不够:
- 用
curl -I http://localhost:8080/this-does-not-exist看响应头是否含HTTP/1.1 404 Not Found,排除状态码被覆盖 - 在 handler 里加一行
app.Logger().Infof("404 hit for path: %s", ctx.Path()),确认函数真被调用 - 如果用了模板,检查
ctx.ViewData传参是否拼写一致,{{.Message}}和ctx.ViewData("message", "xxx")中的 key 大小写必须完全匹配
最易被忽略的是:泛匹配路由(如 /api/v1/{path:path})会吞掉所有子路径,导致 404 处理器完全失效——这类路由应放在最后注册,且明确限定方法,避免误伤。










