如何在Golang中处理JSON字段缺失_Golangjson解析字段校验方法
技术百科
P粉602998670
发布时间:2026-01-01
浏览: 次 json.Unmarshal字段缺失时不报错,将结构体字段设为零值;可用指针类型判nil、json.RawMessage手动检查或自定义UnmarshalJSON实现精准追踪。
JSON字段缺失时 json.Unmarshal 默认行为是什么
Go 的 json.Unmarshal 在遇到 JSON 中缺少某个字段时,**不会报错**,而是将对应结构体字段设为零值(0、""、nil、false 等)。这容易掩盖数据不完整问题,尤其在 API 请求或配置解析场景中导致静默失败。
例如,若结构体定义了 ID int,但 JSON 中没传 "id",ID 就变成 0 —— 你无法区分这是“用户真传了 0”,还是“字段根本没传”。
- 零值覆盖不可逆,原始缺失状态丢失
- 没有内置开关让
Unmarshal在字段缺失时报错 -
omitempty标签只影响序列化(Marshal),对反序列化无作用
用指针字段 + nil 判断识别字段是否缺失
最直接可控的方式:把需要校验是否存在的字段声明为指针类型。JSON 解析器只有在字段存在时才会分配内存并赋值;缺失时保持 nil。
type User struct {
ID *int `json:"id"`
Name *string `json:"name"`
Age *int `json:"age"`
}
// 示例 JSON: {"name": "Alice"} → ID 和 Age 为 nil,Name 指向 "Alice"
- 检查
u.ID == nil即可确认"id"字段未提供 - 注意:指针字段需手动解引用(如
*u.ID),且要先判空避免 panic - 适合必填字段校验,但会让结构体变“重”,尤其嵌套多层时指针易出错
用 json.RawMessage 延迟解析 + 手动字段存在性检查
当需要统一判断多个字段是否存在,或字段类型动态(比如可能是 string 或 number),可用 json.RawMessage 先原样捕获字节,再按需解析并检查 key 是否存在。
type Payload struct {
Data json.RawMessage `json:"dat
a"`
}
var p Payload
if err := json.Unmarshal(b, &p); err != nil {
return err
}
// 转成 map[string]json.RawMessage 检查 key
var m map[string]json.RawMessage
if err := json.Unmarshal(p.Data, &m); err != nil {
return err
}
if _, ok := m["timeout"]; !ok {
return fmt.Errorf("missing required field: timeout")
}
- 能精确知道哪些 key 存在/不存在,不依赖零值语义
- 适合做前置校验(如中间件里统一拦截缺失字段)
- 性能略低(两次 Unmarshal),且需额外处理类型转换逻辑
自定义 UnmarshalJSON 实现字段存在性钩子
对关键结构体,可实现 UnmarshalJSON 方法,在解析过程中记录哪些字段被设置。配合私有标记字段(如 seenID bool)完成精准追踪。
type User struct {
ID int `json:"id"`
Name string `json:"name"`
seenID bool
seenName bool
}
func (u *User) UnmarshalJSON(data []byte) error {
type Alias User // 防止无限递归
aux := &struct {
ID *int `json:"id"`
Name *string `json:"name"`
*Alias
}{
Alias: (*Alias)(u),
}
if err := json.Unmarshal(data, &aux); err != nil {
return err
}
if aux.ID != nil {
u.seenID = true
u.ID = *aux.ID
}
if aux.Name != nil {
u.seenName = true
u.Name = *aux.Name
}
return nil
}
- 保留原始字段类型(非指针),同时获得字段是否被设置的能力
- 代码量稍多,但复用性和类型安全更好
- 注意别漏掉所有字段,否则可能误判为“未设置”
RawMessage 最灵活,自定义 UnmarshalJSON 最精确。实际项目里,建议优先用指针字段,仅在必要时才上更重的方案。
# 是在
# 这是
# 多个
# 自定义
# 为零
# 时才
# js
# json
# go
# golang
# 递归
# String
# int
# 字节
# 标准库
# 指针
# nil
# 序列化
# 报错
# red
# 结构体
# 指针类型
# 类型转换
# 中间件
# bool
# 是否存在
# number
相关栏目:
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
AI推广<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
SEO优化<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
技术百科<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
谷歌推广<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
百度推广<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
网络营销<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
案例网站<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
精选文章<?muma echo $count; ?>
】
相关推荐
- VSC怎样在VSC中调试PHPAPI_接口调试技巧
- Win10如何备份注册表_Win10注册表备份步骤
- Windows10如何更改日期格式_Win10区域
- Windows10电脑怎么连接蓝牙设备_Win10
- Win11怎么关闭粘滞键_彻底禁用Windows
- Python包结构设计_大型项目组织解析【指导】
- Windows10电脑怎么设置自动连接WiFi_W
- 如何在 Go 中调用动态链接库(.so)中的函数
- 如何使用Golang搭建Web开发环境_快速启动H
- Win11怎么关闭VBS安全性_Windows11
- php增删改查需要哪些扩展_开启mysqli或pd
- Win11怎么关闭键盘按键音_Win11禁用打字声
- php删除数据怎么软删除_添加is_del字段标记
- Bpmn 2.0的XML文件怎么画流程图
- Win11怎么设置触控板手势_Windows11三
- Win11怎么设置指纹解锁 Win11笔记本录入指
- Win10怎样清理C盘Steam游戏缓存_Win1
- Avalonia如何实现跨窗口通信 Avaloni
- Win10怎么卸载金山毒霸_Win10彻底卸载金山
- Win11如何设置鼠标灵敏度_Win11鼠标灵敏度
- php8.4匿名类怎么用_php8.4匿名类创建与
- Windows10蓝屏代码DPC_WATCHDOG
- Mac如何与安卓手机传文件_Mac和Android
- Win10怎样卸载TeamViewer_Win10
- Python模块的__name__属性如何由导入方
- Win11怎么更改任务栏位置_修改注册表将Win1
- 如何使用Golang实现负载均衡_分发请求到多个服
- PHP主流架构怎么处理表单验证_规则与自定义【技巧
- Win11时间格式怎么改成12小时制 Win11时
- 如何使用Golang反射创建map对象_动态生成键
- Windows10系统怎么查看设备管理器_Win1
- Python文本编码与解码_跨平台解析说明【指导】
- Windows怎样关闭桌面弹窗广告_Windows
- c# await 一个已经完成的Task会发生什么
- windows如何测试网速_windows系统网络
- Windows怎样拦截WPS弹窗广告_Window
- Win11怎么开启智能存储_Windows11存储
- Python函数缓存机制_lru_cache解析【
- 为什么Go建议使用error接口作为错误返回_Go
- Go 中实现 Python urllib.quot
- Win10怎么关闭自动更新错误重启 Win10策略
- 如何使用Golang sync.Map实现并发安全
- c++的static关键字有什么用 静态变量和静态
- Python对象生命周期管理_创建销毁说明【指导】
- php下载安装后swoole扩展怎么安装_异步框架
- Win10文件历史记录怎么用 Win10开启自动备
- c++中explicit(bool)的用法 c++
- PythonGIL机制理解_多线程限制解析【教程】
- LINUX怎么进行文本内容搜索_Linux gre
- Windows10系统怎么查看防火墙状态_Win1

a"`
}
var p Payload
if err := json.Unmarshal(b, &p); err != nil {
return err
}
// 转成 map[string]json.RawMessage 检查 key
var m map[string]json.RawMessage
if err := json.Unmarshal(p.Data, &m); err != nil {
return err
}
if _, ok := m["timeout"]; !ok {
return fmt.Errorf("missing required field: timeout")
}
QQ客服