NotFound handler必须在fiber.New()初始化时通过Config传入,后期赋值或app.Use拦截无效;需手动调c.Status(404),且不可在其中使用异步操作或c.Render()。

NotFound handler 必须在 fiber.New() 初始化时传入
直接写 app.Get("/404", handler) 没用——Fiber 根本不会在路由未匹配时跳过去。它只在所有注册路由都未命中、且中间件链没提前返回响应时,才触发 NotFound 函数。
常见错误是后期调用 app.Config().NotFound = ... 或试图用 app.Use() 拦截 404,这些操作全部无效。
-
NotFound是fiber.Config的字段,只能在fiber.New(&fiber.Config{...})里一次性设置 - 修改后必须重启服务;浏览器缓存可能让你误判页面是否生效
- 别把
NotFound和ErrorHandler混为一谈:前者只管“没路由匹配”,后者负责捕获 panic 或fiber.Error
必须手动调用 c.Status(404)
浏览器看到 HTML 内容但状态码仍是 200?八成是忘了设状态码。Fiber 不会自动根据 NotFound 这个函数名推断你想发 404。
c.SendString()、c.JSON()、c.Render() 等方法默认都用 200,不显式调 c.Status(404),前端就收不到正确语义。
立即学习“go语言免费学习笔记(深入)”;
使用 uber-go/dig 在 Golang 中实现依赖注入——基于反射容器,提供 Provide/Invoke、dig.In/dig.Out 参数与结果对象,支持命名依赖等
- 调试时可用
fmt.Println(c.Response().StatusCode())确认实际发出的状态码 - 别依赖模板引擎或中间件自动补状态码——它们不知道你当前在处理 404
- 如果用了
c.Render("404", nil),要先c.Status(404),再c.Render(),且必须捕获error防止 panic
用模板渲染时不能直接调 c.Render()
c.Render() 是异步方法,而 NotFound 要求同步返回 error。直接写会导致编译通过但运行时 panic,整个请求崩溃,连 404 状态都发不出去。
安全做法是手动调用模板引擎的 Execute() 方法,并自己处理错误:
NotFound: func(c *fiber.Ctx) error {
c.Status(404)
if err := c.Locals("html").(*html.Engine).Execute(c, "404.html", nil); err != nil {
return c.SendStatus(404) // fallback
}
return nil
},
- 确保
c.Locals("html")存在且类型正确(取决于你如何注册html.New()) - 不要在
NotFound里await、defer或调用任何异步 I/O(如 DB 查询、HTTP 请求) - 如果不用模板,直接
c.SendString()最轻量、最不易出错
StrictRouting 导致 /users/ 和 /users 都 404?不是配置问题,是路径没对齐
注册了 app.Get("/users", h),但访问 /users/ 返回 404?这不是 NotFound 配置失效,而是 Fiber 把这两个路径当成完全不同的路由——因为 StrictRouting: true 是默认行为。
解决思路不是关掉 StrictRouting(那会让 /users/:id 和 /users/123 匹配混乱),而是统一入口:
- 加一个前置中间件,检测以
/结尾且非根路径的请求,用c.Redirect(strings.TrimSuffix(c.Path(), "/"), fiber.StatusMovedPermanently)301 跳转 - 确保该中间件在所有
app.Get()、app.Post()之前注册 - 保留 query string:用
c.Request().URI().FullURI()拆解并重建 URL,避免丢掉?page=2
真正容易被忽略的是:404 页面本身也得能被正确路由到——如果重定向逻辑有 bug,或者静态资源路径写错,NotFound 函数甚至都进不去。


















