必须分两步解码:先解析外层结构,将嵌套json字段声明为string或json.rawmessage,再对其内容单独调用json.unmarshal解析为[]mystruct;直接解到切片会报“cannot unmarshal string into go value of type []mystruct”。

嵌套 JSON 字符串里含数组,但顶层不是标准 JSON 数组
常见场景是:API 返回一个 {"data": "[{...},{...}]"} 这样的结构——data 字段值本身是个 JSON 字符串,而不是直接的 JSON 数组。直接用 json.Unmarshal 解到 []MyStruct 会失败,报错 json: cannot unmarshal string into Go value of type []MyStruct。
必须先解出字符串,再二次解析。典型错误是试图跳过中间步骤,或误用 json.RawMessage 而没做类型转换。
- 先定义外层结构体,把
data字段声明为string(不是json.RawMessage,除非你确定后续要延迟解析) - 调用
json.Unmarshal解第一层,拿到data的字符串内容 - 再对这个字符串调用
json.Unmarshal,目标是[]MyStruct
使用 json.RawMessage 避免重复解析或保留原始字段
如果嵌套 JSON 字符串来自不可信来源,或者你想复用原始字符串(比如透传、审计、校验),用 json.RawMessage 更稳妥。它不解析内容,只做字节拷贝,适合“暂存待处理”场景。
注意:json.RawMessage 是 []byte 别名,不能直接当 string 用;转成字符串需显式 string(raw),且要确保 UTF-8 安全(一般 JSON 都是)。
- 外层结构体字段类型设为
json.RawMessage - 第一次
json.Unmarshal后,用json.Unmarshal(raw, &slice)解第二层 - 别忘了检查
raw是否为空或非法 JSON,否则第二步 panic
type Response struct {
Data json.RawMessage `json:"data"`
}
var resp Response
json.Unmarshal(b, &resp)
var items []Item
err := json.Unmarshal(resp.Data, &items) // 这里才真正解析嵌套数组
结构体字段标签与 JSON key 不匹配导致解析为空
嵌套 JSON 是字符串,但里面字段名大小写、下划线规则可能和 Go 结构体不一致。比如 JSON 里是 "user_name",而结构体字段写成 UserName string 却没加 json:"user_name" 标签,结果字段始终为空,还查不出错——因为解析过程没报错,只是静默忽略。
- 所有导出字段都必须加
json标签,显式对应 JSON key - 如果 JSON key 含特殊字符(如
@type),标签里直接写json:"@type" - 用
json:",omitempty"要小心:空字符串、零值字段会被跳过,可能导致嵌套结构丢失
JSON 字符串里混有换行、多余空格或 BOM 头
某些后端返回的嵌套 JSON 字符串会带前导空格、换行符,甚至 UTF-8 BOM(\uFEFF)。这些字符让 json.Unmarshal 直接报 invalid character ... 错误,但错误位置指向开头,容易误判为 JSON 格式本身有问题。
- 解析前先用
strings.TrimSpace清除首尾空白 - 检测并移除 BOM:
bytes.TrimPrefix(data, []byte("\uFEFF")) - 如果嵌套字符串是 Base64 编码过的(少见但存在),得先
base64.StdEncoding.DecodeString
最省事的做法:在第二次 json.Unmarshal 前,打印或日志记录清理后的字符串前 100 字符,确认格式干净。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











