json.Marshal 返回空对象 {} 是因字段未导出:首字母小写字段(如 name)无法被反射访问,需改为大写(Name)并配合 json:"name" 标签;嵌套结构体每层均需遵守此规则。

json.Marshal 返回空对象 {} 是字段未导出
这是最常见也最容易被忽略的问题:结构体字段名首字母小写(如 name、configs),导致 json.Marshal 根本读不到值,直接返回 {}。Go 的反射机制只允许外部包访问导出字段(首字母大写),和 json 标签是否存在、内容是否正确完全无关。
解决方法很简单:
- 把字段名改成首字母大写,例如
name→Name,local_address→LocalAddress - 保留
json标签控制输出键名,比如Name string `json:"name"` - 嵌套结构体每一层都要检查——哪怕外层字段大写,内层字段小写也会被跳过
- 不要用
unsafe或反射强行读取未导出字段,这会破坏类型安全且不可靠
json.Marshal 返回 error 是遇到了不支持的类型
json.Marshal 返回非 nil 的 error,基本只有一类原因:值里包含无法序列化的 Go 类型。它不会因为字段为空或 nil 指针报错(nil 指针会编码为 null),但碰到以下类型就会失败:
-
func类型(比如误把方法接收器或回调函数塞进结构体) -
chan、map[interface{}]T、unsafe.Pointer -
interface{}底层值是上述任意一种类型 - 自定义类型实现了
MarshalJSON()但方法 panic 或返回非法 JSON
典型错误信息:json: unsupported type: func()、json: unsupported type: map[interface {}]string。排查建议:
立即学习“go语言免费学习笔记(深入)”;
- 逐个字段测试
json.Marshal(field),尤其关注map、interface{}和嵌套结构体 - 确认所有
map的键类型是可比较的基本类型(string、int、bool等) - 避免在待序列化结构体中直接嵌入
*sql.DB、http.ResponseWriter这类运行时对象
time.Time 和循环引用会让 Marshal 表现异常
time.Time 字段本身能被正常序列化,但容易踩两个坑:
- 未初始化的零值
time.Time{}配合某些json标签(比如string)可能触发json: invalid use of ,string struct tag错误 - 把
time.Time存进map[string]interface{}再调用json.Marshal,它不会自动调用你为time.Time实现的MarshalJSON()
循环引用则更危险:struct A 包含指向 B 的指针,B 又包含指向 A 的指针,json.Marshal 会无限递归,最终 panic:runtime: goroutine stack exceeds 1000000000-byte limit。标准库不检测也不处理这种环。
应对方式:
- 对时间字段优先用
*time.Time+omitempty,或显式实现MarshalJSON()返回带引号的字符串 - 循环引用必须提前断开——比如用 ID 替代指针,或在序列化前手动构建无环视图
- 不要依赖第三方库自动检测循环;Go 标准库不提供该能力,加了也是伪安全感
嵌套结构体字段丢失或反序列化后为零值
看起来结构体嵌套很深,但 JSON 输出里某一层突然消失,或者 json.Unmarshal 后字段全是零值(""、0、nil),大概率不是深度问题——Go 的 json 包默认支持远超常规需求的嵌套层级(内部最大深度约 10000 层)。
真正原因是类型不匹配或字段未导出:
- JSON 中的
"id": 123是 number,但结构体字段定义为Id string→ 静默跳过,不报错,Id保持"" - 结构体字段小写(
message),即使嵌套再深,json包也看不到它 - 字段类型虽匹配,但 JSON key 名与结构体字段名 /
json标签不一致(比如标签写成`json:"msg_id"`,但 JSON 里是"message_id")
调试技巧:
- 先用
json.Valid([]byte)确认输入 JSON 合法 - 打印原始字节,对照结构体字段名和标签逐项比对
- 对关键字段启用
json.Decoder.DisallowUnknownFields(),让不匹配字段立刻报错而不是静默丢弃
导出规则是硬边界——小写字段在 JSON 编解码中就是不存在。别指望标签、反射或工具链绕过它。


















