c.json()最稳妥,因其自动调用json.marshal并设置content-type: application/json及状态码200;手动json.marshal+sendstring易漏设头致前端解析失败。

直接用 c.JSON() 就行,别自己 json.Marshal + c.SendString(),否则 Content-Type 会漏设,前端解析失败。
为什么 c.JSON() 是最稳妥的 JSON 返回方式
c.JSON() 内部自动调用 json.Marshal 并设置 Content-Type: application/json,状态码默认 200,你只需传状态码(可选)和任意 Go 值。
- 传入不可序列化类型(如
func、chan、未导出字段且没加json:tag)会返回500和错误信息:json: unsupported type: xxx - 常见翻车点:把 GORM 模型直接传给
c.JSON(),而模型含gorm.Model或方法字段 —— Fiber 不会自动过滤 - 解决办法:
json:"-"忽略字段、用匿名结构体投影、或定义专用 DTO 结构体 - 别写
c.Status(200).SendString(string(b)),SendString()不设Content-Type,前端可能当文本处理
如何安全返回含 time.Time 或 NaN 的 JSON
Fiber 默认用标准 encoding/json,不支持自定义时间格式(如 "2006-01-02")或 NaN 处理。真有这类需求,得换底层编码器。
- 推荐替换为
github.com/json-iterator/go或goccy/go-json,性能更好、选项更多 - 替换后所有
c.JSON()调用(包括错误响应如c.Status(500).JSON(fiber.Map{"error": "xxx"}))都会走新逻辑 - 注意:这不是“加个配置”就能生效的事——必须在
fiber.New()初始化时注入自定义 encoder,否则无效 - 简单场景下,优先用 DTO 结构体 +
json:tag 控制输出,比堆砌 encoder 配置更清晰
c.Status(code).JSON() 和 c.JSON(code, v) 有啥区别
本质一样,c.Status(code).JSON(v) 是链式写法,等价于 c.JSON(code, v);但链式调用容易误操作。
-
c.Status(404).SendString("not found")后再跟c.JSON()会 panic:http: multiple response.WriteHeader calls -
Status()只设状态码,不发响应;真正触发发送的是后续的JSON()、SendString()等 - 动态状态码建议直接用
c.JSON(statusCode, data),语义清晰、不易出错 - 如果中间件里写了
c.Status(401).Send()却忘了return,后续 handler 仍会执行,可能重复响应甚至 panic
XML 响应不能靠 c.JSON(),得手动处理
Fiber 默认不支持 XML 响应,c.XML() 不存在;要返回 XML,必须自己序列化并设头。
- 用
xml.Marshal()序列化结构体,再用c.Status(200).SendBytes()发送字节 - 必须手动设
Content-Type: application/xml或text/xml,否则前端无法识别 - 结构体字段需导出(首字母大写),且带
xml:tag,比如ID int `xml:"id"` - 别试图用
c.BodyParser()反向“伪造” XML 响应——它只用于请求解析,和响应无关
最容易被忽略的是:所有手动序列化(JSON/XML)都绕过了 Fiber 的默认 Content-Type 自动设置逻辑,漏设头 = 前端解析失败。哪怕只差一行 c.Set("Content-Type", "..."),也可能让整个接口在某些客户端上失效。











