NotFound配置不生效最常见原因是误将其当普通路由注册,或未在fiber.New()中通过Config传入;必须同步设置状态码、避免异步操作、正确处理模板错误,并确保ErrorHandler与中间件顺序合理。

为什么 NotFound 配置不生效
最常见原因是把 NotFound 当成普通路由来写,比如加了 app.Get("/404", ...) —— Fiber 根本不会在路由未匹配时跳过去。它只在所有注册路由都未命中、且中间件链没提前返回响应时才触发 NotFound handler。
另一个高频坑是:handler 里调用了 c.Render("404", nil) 却没处理错误,而模板引擎加载失败时会 panic,导致整个请求崩溃,连状态码都发不出去。更隐蔽的是,忘了显式调用 c.Status(404),浏览器看到的是 HTML 内容,但响应状态码仍是 200。
- 确保
NotFound是在fiber.New()初始化时通过fiber.Config传入,不能后期覆盖 - 避免在
NotFound函数里直接调用异步方法(如c.Render),必须自己捕获 error 并 fallback - 修改配置后记得重启服务;浏览器缓存可能让你误判页面是否生效
如何正确设置 NotFound 和 ErrorHandler
NotFound 只管“没路由匹配”,ErrorHandler 负责捕获 panic、显式抛出的 fiber.Error 或其他未处理异常——两者职责分明,必须共存才能覆盖全部错误场景。
示例中 NotFound 直接返回字符串,轻量且不易出错:
app := fiber.New(fiber.Config{
NotFound: func(c *fiber.Ctx) error {
c.Status(404)
return c.SendString("<h1>⛔ 页面未找到</h1>")
},
ErrorHandler: func(c *fiber.Ctx, err error) {
if e, ok := err.(*fiber.Error); ok {
c.Status(e.Code)
} else {
c.Status(500)
}
return c.SendString("<h1>" + c.Response().StatusCode() + " 错误</h1>")
},
})
-
NotFound是同步 handler,不能 await、不能 defer,务必手动设状态码 -
ErrorHandler的err参数可能是*fiber.Error(如fiber.NewError(404, "...")),也可能是 panic 后 recover 出来的任意值 - 不要在
ErrorHandler里再调panic,否则会二次崩溃
用模板引擎渲染自定义 HTML 文件
如果你已配置了 html.New() 模板引擎,想复用 views/404.html,就不能直接在 NotFound 里写 c.Render("404", nil) —— 因为 Render 是异步方法,NotFound handler 要求同步返回 error。
安全做法是手动调用模板引擎的 Execute 方法,并捕获错误:
NotFound: func(c *fiber.Ctx) error {
c.Status(404)
if err := app.Settings.Views.Execute(c.Context(), c.Response().BodyWriter(), "404", nil); err != nil {
return c.SendStatus(404) // fallback
}
return nil
},
- 注意:这里用的是
app.Settings.Views.Execute,不是c.Render -
c.Response().BodyWriter()是底层写入器,Execute直接往里面写,不经过 Fiber 的响应包装逻辑 - 如果模板路径不对或语法错误,
Execute会返回 error,必须处理,否则 handler panic
容易被忽略的中间件顺序问题
ErrorHandler 不会捕获被中间件吞掉的 panic。比如你启用了 middleware.Recover(),但它内部已经 recover 并返回了默认错误页,后续就根本走不到你的 ErrorHandler。
典型错误配置:
app.Use(middleware.Recover()) // ❌ 这个中间件会提前终止 panic 流程 app.Use(customMiddleware()) app.Use(middleware.Logger()) // 你的 ErrorHandler 在 fiber.New() 里,但此时已无效
-
Recover中间件应尽量靠后,或干脆不用,由ErrorHandler统一接管 - 如果必须用
Recover,要确保它不返回响应,而是把 error 重新抛给ErrorHandler -
Logger、RequestID等中间件建议放在Recover前,否则 panic 发生时日志可能缺失


















