最可靠的方式是直接调用 c.status() 显式设置状态码,且必须在写响应体前或同时调用;c.json() 等方法不自动修改状态码,默认为 200。

直接调用 c.Status() 是最可靠的方式
Fiber 不会自动根据响应方法(如 c.JSON()、c.SendString())推断状态码,200 是默认值。想设 404、500、302 等,必须显式调用 c.Status(404),且**必须在写响应体前或同时调用**——否则后续 c.JSON() 可能覆盖它。
常见错误是写了 c.Status(404) 却没 return,接着又执行 c.JSON(data),最终返回 200。正确写法示例:
app.Get("/user/:id", func(c *fiber.Ctx) error {
id := c.Params("id")
if id == "invalid" {
c.Status(404)
return c.SendString("not found") // return 必须紧随其后
}
return c.JSON(map[string]string{"id": id})
})
-
c.Status()返回*Ctx,支持链式调用,比如c.Status(401).SendString("unauthorized") - 状态码必须是整数,不能传字符串,如
c.Status("404")会编译失败 - 如果用了中间件(如鉴权),提前终止流程时也要
return,否则后续 handler 仍会执行并可能重写状态码
c.Send()、c.JSON() 这些方法不自动改状态码
它们只负责写响应体和设置 Content-Type,状态码始终沿用当前 c.Response().StatusCode() 值(默认 200)。你看到的“返回了 JSON 却是 404”现象,基本都是忘了调 c.Status(404)。
特别注意:c.Render()(模板渲染)也一样,不会自动设 404 或 500 —— 模板文件存在与否、渲染是否出错,都由你手动控制状态码。
- 想让 404 页面返回 404 状态,必须在
NotFound配置函数里调c.Status(404) -
c.Redirect()默认发 302,要 301 就得先c.Status(301)再c.Redirect() - 所有
c.XXX()方法都不会抛 panic 来提示状态码遗漏,静默用 200,调试时可用fmt.Println(c.Response().StatusCode())确认
全局错误处理中状态码容易被忽略
fiber.Config{ErrorHandler: } 里拿到的 err 未必自带状态码。Fiber 内部的 *fiber.Error 有 .Code 字段,但第三方 error(比如数据库报错、os.Open 失败)没有。不判断就直接 c.Status(500),会导致本该是 404 的路由未匹配错误也被打成 500。
推荐做法是先类型断言,再 fallback:
ErrorHandler: func(c *fiber.Ctx, err error) error {
if e, ok := err.(*fiber.Error); ok {
c.Status(e.Code)
} else {
c.Status(500)
}
return c.SendString("Oops")
}
- 别在
ErrorHandler里漏掉c.Status()—— 这里设的状态码就是最终响应状态码 -
NotFound和ErrorHandler是两个独立机制:NotFound不进ErrorHandler,除非你在里面手动panic或返回非 nil error - 如果用了
middleware.Recover(),它内部会调ErrorHandler,所以状态码逻辑必须在这里统一收口
WebSocket 升级请求不能用 c.Status()
WebSocket 握手是 HTTP 协议的一部分,但一旦升级成功,连接就脱离 HTTP 生命周期。c.Status() 只对普通 HTTP handler 有效;在 websocket.New() 的回调函数里调它无效,甚至可能 panic。
WebSocket 连接失败时,前端看到的 event.code(如 1006)由底层 TCP/WS 协议栈决定,不是 HTTP 状态码。想传递业务原因,只能靠关闭前发送文本帧,或在升级前的 HTTP handler 中提前校验并返回 4xx:
app.Get("/ws/:room/:id", func(c *fiber.Ctx) error {
roomID := c.Params("room")
if !validRoom(roomID) {
c.Status(400)
return c.SendString("invalid room")
}
// 后续才走 websocket.New(...)
})
- WebSocket 的
c.Close()不接受状态码参数,v2 版本暂不支持自定义关闭码(如 4001) - 浏览器
WebSocket对象的event.code和event.reason在服务端主动关闭时通常为空,这是协议限制,不是 Fiber bug - 真正需要带状态的,应放在升级前的普通路由里拦截,而不是试图在 WS 连接中“返回 HTTP 状态”











