根本原因是响应头缺失Content-Type的charset声明,Go默认输出UTF-8字节但客户端未获知编码;需显式设置Header("Content-Type", "application/json; charset=utf-8"),并确保源文件、中间件、代理均不破坏该声明。
根本原因不是 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")
net/http 原生不加,Gin 默认加但某些中间件可能覆盖)curl -v 或浏览器开发者工具 Network 面板确认响应头中 Content-Type 是否含 charset=utf-8
开发调试时常用 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())
c.JSON(200, data) 内部已设置 Content-Type: application/json; charset=utf-8,但仍有乱码,大概率是中间件或自定义逻辑干扰了响应头。
c.JSON() 前调用了 c.Header("Content-Type", ...) 或 c.Data() 等底层写入方法c.Render() 自定义模板,需手动设置 charset;c.JSON() 不走该流程json:"name,string" 且值为非 UTF-8 字节,也会触发编码异常服务端已正确返回 UTF-8 JSON 和响应头,但 JS 中 response.json() 解析后中文仍是乱码,问题通常出在传输层或前端解析时机。
charset utf-8; 在 location 块中,可能强制重写响应头,反而冲突response.text() 再 
JSON.parse() —— 这绕过了浏览器内置的 charset 检测逻辑,应直接用 response.json()
Content-Type 未被覆盖;Response Preview 若显示乱码但 Raw 显示正常,说明是前端渲染问题而非传输问题最易忽略的是:本地测试时用 go run main.go 启动,但文件本身保存为 GBK 编码(尤其 Windows 记事本),导致源码里中文字符串字面量就是 GBK 字节,json.Marshal 只是原样编码输出,结果服务端发的是 GBK 字节流却声明了 UTF-8 charset —— 浏览器照着 UTF-8 解,必然乱码。务必统一用 UTF-8 编码保存 Go 源文件。