json.MarshalIndent缩进异常主因是参数误用或输入非原生结构:prefix为空时每行无前置缩进,indent不匹配导致层级错乱;必须传struct/map等原生数据,不可传已序列化的字符串;中文转义需改用json.Encoder配合SetIndent与SetEscapeHTML(false)。

为什么 json.MarshalIndent 输出的缩进看起来不对?
直接调用 json.MarshalIndent 时,如果传入的 prefix 和 indent 参数为空字符串或空格不匹配,会导致换行存在但缩进丢失,看起来像“没格式化”。它不是自动美化任意 JSON 字符串,而是按结构层级插入换行和缩进 —— 所以输入必须是 Go 原生数据结构(如 map[string]interface{} 或 struct),不能是已序列化的 string。
-
prefix是每行开头的固定前缀(常设为"") -
indent是每一级嵌套使用的缩进字符串(如" "或"\t") - 若把
json.Marshal的输出字节再喂给MarshalIndent,会得到双引号包裹的字符串,而非结构化缩进
如何正确传参并避免中文乱码?
Go 的 json 包默认将非 ASCII 字符(如中文)转义为 \uXXXX 形式。这不是 bug,是 JSON 标准兼容行为。要保留原始中文,需用 json.Encoder 配合 SetEscapeHTML(false),但 MarshalIndent 本身不提供该开关 —— 所以得绕一下:
- 先用
json.MarshalIndent得到[]byte - 再用
strings.ToValidUTF8(Go 1.19+)或正则替换(旧版)处理 \u 转义(不推荐,易出错) - 更稳妥的做法:改用
json.NewEncoder+SetEscapeHTML(false)+ 自定义缩进写入器(见下一点)
想输出带缩进又不转义中文,该用 json.Encoder 还是 MarshalIndent?
两者定位不同:MarshalIndent 是纯内存操作,返回 []byte;Encoder 是流式写入,支持设置 SetEscapeHTML(false),但**不内置缩进逻辑**。所以实际组合用法是:
enc := json.NewEncoder(os.Stdout)
enc.SetEscapeHTML(false)
enc.SetIndent("", " ") // 这里才是关键:等效于 MarshalIndent 的两个参数
enc.Encode(data) // data 必须是 struct/map 等,不能是 []byte
-
SetIndent(prefix, indent)的行为和MarshalIndent完全一致 - 必须在
Encode()前调用,否则无效 - 对
nil、数字、布尔等基础类型也生效,但无缩进效果(单行)
嵌套 struct 中字段名含下划线或大小写不一致怎么办?
JSON 序列化依赖 struct tag:json:"field_name"。如果字段名是 UserName 但想输出 user_name,不加 tag 就会输出 UserName(首字母大写暴露);如果 tag 写成 json:"user_name,string",还会触发字符串强制转换(比如把 int 变成 "123")。
- 导出字段(首字母大写)才可被
json包访问,未导出字段会被忽略 - 想跳过某个字段,用
json:"-" - 想保持原名但小写,只能重命名字段(如
UserName→Username)或用自定义MarshalJSON方法 - 别滥用
stringtag:它只对数值/布尔类型有效,对 struct 或 map 会 panic
缩进本身不解决字段映射问题,但错误的 struct tag 会让格式化后的 JSON 字段名不符合预期,容易误以为是缩进失效。


















