Go中json.Unmarshal解析失败主因是字段类型与JSON值不匹配或json标签错误,需显式标注标签、用,string处理字符串数字、指针容null、自定义time类型支持多格式,并记录原始错误上下文。

Go 中用 json.Unmarshal 解析失败却只报 json: cannot unmarshal ...
错误信息太笼统,实际原因常是结构体字段类型不匹配或标签写错。比如 JSON 里是字符串 "123",而结构体字段是 int,Go 默认不自动转换;又或者用了 json:"user_id,string" 却漏掉 ,string 后缀,导致解析失败。
- 先确认 JSON 原文字段值类型(字符串/数字/布尔/空值),再比对 Go 字段类型是否兼容
- 整数字段想接受字符串形式数字?加
,string标签:UserID int `json:"user_id,string"` - 字段可能为
null?别用基础类型,改用指针或sql.NullInt64等可空类型 - 嵌套对象缺失时 panic?给结构体字段加
omitempty不解决缺失问题,得靠字段类型容错(如用*string)
错误包裹后丢失原始 JSON 解析上下文
用 fmt.Errorf("parse user failed: %w", err) 包裹 json.Unmarshal 错误,再打印时只剩顶层提示,看不到具体哪行、哪个 key 出问题。Go 1.20+ 的 errors.Unwrap 或 %+v 也救不回原始位置信息。
- 别只依赖
%w:在包裹前先记录原始错误和输入片段,例如:log.Printf("failed to unmarshal JSON %q: %v", string(data[:200]), err) - 想保留字段路径?自己实现一个带上下文的 wrapper 类型,或用第三方库如
github.com/mitchellh/mapstructure(它报错带 key 路径) - 调试阶段直接用
json.RawMessage延迟解析,把不确定结构的部分先存下来,后续按需解,避免一上来就崩
结构体字段名大小写和 JSON key 对不上
Go 结构体字段必须首字母大写才可导出,但 JSON key 是小写的(如 user_name),没写 json: 标签就会匹配失败,且不报错——字段保持零值,静默丢数据。
- 永远显式写
json标签,哪怕和字段名一致:UserName string `json:"user_name"` - 别依赖结构体命名习惯(如
UserName自动转user_name),Go 的json包不做蛇形/驼峰自动转换 - 用 IDE 插件或
go vet -tags=json(需 Go 1.21+)检查未标注的导出字段,提前发现遗漏
反序列化含时间字段的 JSON 时格式混乱
time.Time 默认只认 RFC 3339 格式(如 "2023-01-01T00:00:00Z"),遇到 "2023-01-01" 或 "1672531200" 直接报错,且错误信息不提格式问题。
立即学习“go语言免费学习笔记(深入)”;
- 不要直接用
time.Time字段,自定义类型实现UnmarshalJSON方法,支持多种格式解析 - 常见做法:封装一个
type JSONTime time.Time,在UnmarshalJSON里按顺序尝试time.Parse多个 layout - 注意时区:
time.Unix(1672531200, 0)默认 UTC,若原始数据是本地时间,得手动加偏移,否则时间差 8 小时
,string 或少写的 json:。










