Go语言API响应JSON反序列化:空字符串字段兼容问题
解决Go中JSON反序列化子结构体与空字符串不兼容的问题
问题的核心是API返回的字段类型不一致:有数据时是JSON对象,无数据时是空字符串,而Go标准库的JSON解析器无法自动将字符串转换为结构体类型,哪怕用指针或omitempty标签也不行——omitempty仅影响序列化时的零值忽略,指针则期望输入是null而非字符串。
解决方案:为子结构体实现自定义UnmarshalJSON方法
通过自定义反序列化逻辑,让结构体既能处理JSON对象,也能处理空字符串(甚至null)的情况。
1. 定义子结构体并实现自定义反序列化
以CaseReport为例,PrimaryContact可以复用同样的逻辑:
package main import ( "encoding/json" "fmt" ) type CaseReport struct { ReportID string `json:"report_id"` Content string `json:"content"` } // 自定义UnmarshalJSON,处理空字符串和对象两种输入 func (cr *CaseReport) UnmarshalJSON(data []byte) error { inputStr := string(data) // 处理空字符串或null的情况 if inputStr == `""` || inputStr == "null" { *cr = CaseReport{} // 置为零值结构体 return nil } // 用别名避免递归调用当前UnmarshalJSON方法 type Alias CaseReport return json.Unmarshal(data, (*Alias)(cr)) } // 主响应结构体 type APIResponse struct { Result struct { PrimaryContact CaseReport `json:"primary_contact"` CaseReport CaseReport `json:"case_report"` } `json:"result"` }
2. 测试两种场景
- 场景1:有数据的API响应
func main() { // 模拟有数据的响应 validResp := `{ "result": { "primary_contact": {"report_id": "C001", "content": "John Doe"}, "case_report": {"report_id": "R001", "content": "Lost item report"} } }` var resp1 APIResponse if err := json.Unmarshal([]byte(validResp), &resp1); err != nil { fmt.Println("解析有数据响应失败:", err) return } fmt.Printf("有数据时的CaseReport: %+v\n", resp1.Result.CaseReport) }
- 场景2:无数据的API响应
func main() { // 模拟无数据的响应(空字符串) emptyResp := `{ "result": { "primary_contact": "", "case_report": "" } }` var resp2 APIResponse if err := json.Unmarshal([]byte(emptyResp), &resp2); err != nil { fmt.Println("解析空字符串响应失败:", err) return } fmt.Printf("空字符串时的CaseReport: %+v\n", resp2.Result.CaseReport) }
为什么之前的方法无效?
omitempty标签:仅在序列化结构体时忽略零值字段,对反序列化没有作用。- 子结构体设为指针:Go的JSON解析器仅会将
null转换为nil指针,但无法处理空字符串"",因此仍会抛出类型不匹配的错误。
内容的提问来源于stack exchange,提问作者Maria Villanueva
相关产品推荐
相关产品推荐

