根本原因是响应头缺失Content-Type的charset声明,Go默认输出UTF-8字节但客户端未获知编码;需显式设置Header("Content-Type", "application/json; charset=utf-8"),并确保源文件、中间件、代理均不破坏该声明。

Go HTTP 返回 JSON 时中文显示为 或乱码
根本原因不是 Go 本身编码错误,而是响应头缺失 Content-Type 的字符集声明。Go 的 json.Marshal 默认输出 UTF-8 字节,但浏览器或客户端若没收到 Content-Type: application/json; charset=utf-8,可能按 ISO-8859-1 或系统默认编码解析,导致中文变问号或乱码。
- 务必在写响应前显式设置响应头:
w.Header().Set("Content-Type", "application/json; charset=utf-8") - 不要依赖框架自动添加 charset(如
net/http原生不加,Gin 默认加但某些中间件可能覆盖) - 用
curl -v或浏览器开发者工具 Network 面板确认响应头中Content-Type是否含charset=utf-8
使用 json.MarshalIndent 导致响应体开头多出空格或换行
开发调试时常用 json.MarshalIndent 格式化输出,但它会在 JSON 前插入缩进和换行(比如 \n {),而 HTTP 响应体开头若出现空白字符,部分严格解析的客户端(如某些嵌入式 HTTP 库、Postman 的某些模式)会直接报解析失败或丢弃首字符,表现为乱码或无效 JSON。
- 生产环境禁用
json.MarshalIndent,只在日志或调试接口中使用 - 若必须格式化响应,确保不破坏响应流:先
json.Marshal得到字节切片,再用json.Indent处理,最后整体写入w.Write - 注意
http.ResponseWriter一旦调用WriteHeader或首次Write,响应头即锁定,不能再改Content-Type
data := map[string]interface{}{"msg": "你好"}
b, _ := json.Marshal(data)
var out bytes.Buffer
json.Indent(&out, b, "", " ")
w.Header().Set("Content-Type", "application/json; charset=utf-8")
w.Write(out.Bytes())
Gin 框架中 c.JSON() 仍乱码的排查点
c.JSON(200, data) 内部已设置 Content-Type: application/json; charset=utf-8,但仍有乱码,大概率是中间件或自定义逻辑干扰了响应头。
- 检查是否在
c.JSON()前调用了c.Header("Content-Type", ...)或c.Data()等底层写入方法 - 确认没有全局注册的响应拦截中间件(如日志中间件)误写了响应头
- 若用了
c.Render()自定义模板,需手动设置 charset;c.JSON()不走该流程 - Gin v1.9+ 对非 ASCII 字符更严格,若结构体字段 tag 含
json:"name,string"且值为非 UTF-8 字节,也会触发编码异常
前端 fetch 或 axios 接收 JSON 后仍显示乱码
服务端已正确返回 UTF-8 JSON 和响应头,但 JS 中 response.json() 解析后中文仍是乱码,问题通常出在传输层或前端解析时机。
立即学习“go语言免费学习笔记(深入)”;
- 确认响应状态码是 200,且未被代理(如 Nginx)截断或转码:Nginx 默认不修改响应体,但若配置了
charset utf-8;在 location 块中,可能强制重写响应头,反而冲突 - 避免在 fetch 中手动调用
response.text()再JSON.parse()—— 这绕过了浏览器内置的 charset 检测逻辑,应直接用response.json() - Chrome 开发者工具中查看 Response Headers,确认
Content-Type未被覆盖;Response Preview 若显示乱码但 Raw 显示正常,说明是前端渲染问题而非传输问题
最易忽略的是:本地测试时用 go run main.go 启动,但文件本身保存为 GBK 编码(尤其 Windows 记事本),导致源码里中文字符串字面量就是 GBK 字节,json.Marshal 只是原样编码输出,结果服务端发的是 GBK 字节流却声明了 UTF-8 charset —— 浏览器照着 UTF-8 解,必然乱码。务必统一用 UTF-8 编码保存 Go 源文件。










