JSON返回对象列表与单个对象兼容解析问题咨询
处理JSON中数组/单个对象不一致的Go解析方案
这个问题在对接第三方接口时真的很头疼!我给你分享几个Go语言里常用的解决方案,都能完美适配这种时而返回数组、时而返回单个对象的情况:
方案一:自定义UnmarshalJSON方法(推荐长期使用)
这是最优雅的解决方案,通过给你的Det类型实现自定义的反序列化方法,让Go的json包自动处理两种格式的转换。
首先,我们把嵌套的结构体拆出来,让代码更清晰:
// 单个Det项的结构体 type DetItem struct { NItem string `json:"-nItem"` Prod struct { CProd string `json:"cProd"` CEST string `json:"CEST"` Cfop string `json:"CFOP"` UCom string `json:"uCom"` QCom string `json:"qCom"` IndTot string `json:"indTot"` VProd string `json:"vProd"` CEANTrib string `json:"cEANTrib"` UTrib string `json:"uTrib"` NCM string `json:"NCM"` // 补充你的其他字段 } `json:"Prod"` } // 定义Det为DetItem的切片,实现UnmarshalJSON接口 type Det []DetItem func (d *Det) UnmarshalJSON(data []byte) error { // 先尝试解析为数组格式 var detList []DetItem if err := json.Unmarshal(data, &detList); err == nil { *d = detList return nil } // 数组解析失败,尝试解析为单个对象 var detSingle DetItem if err := json.Unmarshal(data, &detSingle); err != nil { return err } // 将单个对象转为切片 *d = []DetItem{detSingle} return nil }
之后定义上层结构体时直接使用Det类型:
type ApiResponse struct { // 其他接口字段 Det Det `json:"det"` }
这样无论接口返回单个det对象还是数组,都会被自动解析为Det切片,后续处理时直接遍历切片即可,完全不用再判断类型。
方案二:先用interface{}接收再手动转换(快速临时处理)
如果只是临时处理某个请求,不想修改结构体定义,可以先用interface{}接收JSON数据,再手动判断类型转换:
type ApiResponse struct { // 其他接口字段 Det interface{} `json:"det"` } // 解析响应 var resp ApiResponse err := json.Unmarshal(jsonBytes, &resp) if err != nil { // 处理解析错误 } // 统一转换为DetItem切片 var detList []DetItem switch raw := resp.Det.(type) { case map[string]interface{}: // 单个对象,转为DetItem后加入切片 itemBytes, _ := json.Marshal(raw) var item DetItem json.Unmarshal(itemBytes, &item) detList = append(detList, item) case []interface{}: // 数组,逐个转换为DetItem for _, itemRaw := range raw { itemBytes, _ := json.Marshal(itemRaw) var item DetItem json.Unmarshal(itemBytes, &item) detList = append(detList, item) } } // 后续直接使用detList即可
这种方法不用修改原有结构体,但代码相对繁琐,适合临时快速解决问题的场景。
方案三:第三方库简化处理
如果你经常遇到这类JSON格式不一致的问题,可以试试mapstructure这类第三方库,它能自动处理单个对象和数组的转换:
import "github.com/mitchellh/mapstructure" type ApiResponse struct { // 其他接口字段 Det []DetItem `json:"det"` } var resp ApiResponse // rawJsonData可以是解析后的map[string]interface{}或原始JSON字节 err := mapstructure.Decode(rawJsonData, &resp)
不过这种方法需要引入第三方依赖,如果你的项目希望保持依赖简洁,方案一仍然是最优选择。
内容的提问来源于stack exchange,提问作者Igor Guedes Rodrigues
相关产品推荐
相关产品推荐

