2023-01-13 18:15:09
在Go语言中处理JSON序列化错误的核心方法是检查json.Marshal和json.Unmarshal返回的error,并根据错误类型进行针对性处理。 以下是具体实现方案和关键注意事项:
一、理解JSON序列化与反序列化的常见错误结构体字段未导出
首字母小写的字段无法被encoding/json包访问,序列化时会直接忽略并可能返回部分数据(但不会报错),反序列化时则完全无法填充。
示例:type User struct { name string // 错误:字段未导出 Age int}
包含不支持的类型
chan、func、复杂指针等类型无法序列化,Marshal会直接报错。
示例:type User struct { Name string Conn chan int // 错误:包含不支持的类型}
JSON格式不匹配
反序列化时,JSON数据的键名、类型或结构与目标结构体不兼容。
示例:{"name": "Alice", "age": "25"} // 错误:age应为数字
JSON语法错误
输入数据存在非法字符、未闭合的引号等语法问题。
示例:{"name": "Alice", "age": 25 // 错误:缺少闭合括号
显式检查错误
即使结构体中存在不可序列化的字段,Marshal也会返回error,必须检查并处理。
示例:type User struct { Name string Age int Conn chan int // 不可序列化的字段}user := User{Name: "Alice", Age: 25, Conn: make(chan int)}data, err := json.Marshal(user)if err != nil { log.Printf("序列化失败: %v", err) // 处理错误:返回默认值、中断流程或忽略特定字段}
忽略不可序列化字段
使用json:"-"标签跳过特定字段的序列化。
示例:type User struct { Name string Age int Conn chan int `json:"-"` // 忽略该字段}
区分错误类型
语法错误:通过json.SyntaxError定位具体位置。
类型不匹配:通过json.UnmarshalTypeError获取期望类型和实际值。
未知字段:使用Decoder.DisallowUnknownFields()严格限制字段。
示例:
var user UserinvalidJSON := `{"name": "Alice", "age": "25"}` // age类型错误err := json.Unmarshal([]byte(invalidJSON), &user)if err != nil { if syntaxErr, ok := err.(*json.SyntaxError); ok { log.Printf("JSON语法错误,位置: %d", syntaxErr.Offset) } else if typeErr, ok := err.(*json.UnmarshalTypeError); ok { log.Printf("类型错误: 期望%s,实际是%s,字段:%s", typeErr.Type, typeErr.Value, typeErr.Field) } else { log.Printf("未知反序列化错误: %v", err) } return}严格字段校验
使用json.Decoder的DisallowUnknownFields()方法禁止多余字段。
示例:decoder := json.NewDecoder(strings.NewReader(jsonData))decoder.DisallowUnknownFields() // 遇到未知字段时报错err := decoder.Decode(&user)
使用DTO结构体
定义专门用于JSON传输的结构体,避免暴露内部实现细节。
示例:type UserDTO struct { Name string `json:"name"` Age int `json:"age"`}
处理可选字段
使用omitempty标签忽略空值,减少冗余数据。
示例:type User struct { Name string `json:"name"` Age int `json:"age,omitempty"` // Age为0时忽略}
中间结构体校验
对关键接口输入使用中间结构体先解析,再映射到业务结构体。
示例:type RawInput struct { Name string `json:"name"` Age string `json:"age"` // 原始输入可能是字符串}func ProcessInput(raw RawInput) (User, error) { age, err := strconv.Atoi(raw.Age) if err != nil { return User{}, fmt.Errorf("age格式错误") } return User{Name: raw.Name, Age: age}, nil}
统一错误拦截
在API层封装JSON解析逻辑,统一返回标准化错误信息。
示例:func ParseJSON(data []byte, target interface{}) error { err := json.Unmarshal(data, target) if err != nil { return fmt.Errorf("JSON解析失败: %v", err) } return nil}