NotFound handler 必须通过 fiber.Config{NotFound: func(c *fiber.Ctx) error {...}} 注册,且需手动调 c.Status(404);它仅在无路由匹配时触发,与 ErrorHandler 各司其职,模板渲染须同步并捕获错误。

NotFound handler 为什么总不触发
最常见的原因是把它当普通路由注册,比如写 app.Get("/404", handler) —— Fiber 根本不会在 404 时跳过去。它只在所有已注册路由都未匹配、且中间件链没提前返回响应时才调用 NotFound。
另一个高频坑是:在 NotFound 函数里直接调 c.Render("404", nil),但模板加载失败时会 panic,导致整个请求崩溃,连状态码都发不出去。
- 必须通过
fiber.Config{NotFound: func(c *fiber.Ctx) error {...}}传入,不能后期覆盖 -
NotFound是同步 handler,不能 await、不能 defer,务必手动调c.Status(404) - 浏览器缓存可能让你误判页面是否生效,改完记得硬刷新或清缓存
如何安全渲染自定义 HTML 模板
如果你用了 html.New() 模板引擎,别在 NotFound 里直接调 c.Render() —— 因为它是异步方法,而 NotFound 要求同步返回 error。
正确做法是手动调用模板引擎的 Execute 方法,并捕获错误:
使用 uber-go/dig 在 Golang 中实现依赖注入——基于反射容器,提供 Provide/Invoke、dig.In/dig.Out 参数与结果对象,支持命名依赖等
立即学习“go语言免费学习笔记(深入)”;
NotFound: func(c *fiber.Ctx) error {
c.Status(404)
if err := c.App().Config().Views.Execute(c, "404", nil); err != nil {
return c.SendStatus(404) // fallback
}
return nil
}
- 避免在
Execute失败后继续写响应,否则可能 panic 或状态码错乱 - 确保
views/404.html文件存在且语法合法,模板错误会在首次请求时暴露 - 不要依赖
c.Render的自动 MIME 推断,NotFound场景下显式设c.Type("text/html")更稳
NotFound 和 ErrorHandler 的分工边界
NotFound 只管“没路由匹配”,ErrorHandler 负责捕获 panic、fiber.Error 或其他未处理异常——两者必须共存,缺一不可。
例如你写了 fiber.NewError(404, "not found"),它不会走 NotFound,而是进 ErrorHandler;而一个完全没注册的路径,才走 NotFound。
-
ErrorHandler的err参数可能是*fiber.Error(含Code字段),也可能是 recover 出来的任意值 - 别在
ErrorHandler里再panic,否则二次崩溃 - 如果想统一返回 JSON 错误,
ErrorHandler里要判断c.Accepts("json"),而不是无脑c.JSON()
常见状态码响应要手动设 Status
很多人写 c.SendString("<h1>404</h1>") 却忘了 c.Status(404),结果浏览器看到 HTML 内容,但响应状态码仍是 200 —— 这会让前端重试逻辑、CDN 缓存、SEO 全部失效。
- 所有自定义错误页 handler 都要先调
c.Status(xxx),再写响应体 - 对
500类错误,建议加c.Set("X-Content-Type-Options", "nosniff")防 MIME 嗅探 - 生产环境慎用
c.SendFile()返回静态错误页,文件缺失会导致 panic,不如用c.SendString()或模板兜底
NotFound 函数是否真的返回了非空 error,也不拦截 handler 内部的 panic —— 所有错误处理逻辑都得你自己写严实。


















