在Golang的开发场景中,JSON是一种非常通用的数据交换格式,我们经常会用到标准库的json包来完成JSON数据的解析操作。解析过程中如果数据不符合预期,就会产生错误,掌握错误捕获方法和错误类型特点,能帮助我们更快定位问题。

Golang JSON解析错误捕获的基本方法
Golang的json包提供的解析函数,比如json.Unmarshal、json.Decoder.Decode等,都会返回第二个错误值,我们只需要判断这个错误值是否为nil,就可以知道解析是否成功。如果错误不为nil,就说明解析过程出现了问题。
下面是一个最基础的JSON解析错误捕获示例:
package main
import (
"encoding/json"
"fmt"
)
func main() {
// 不符合JSON格式的字符串
invalidJSON := `{"name": "test", age: 18}`
var result map[string]interface{}
err := json.Unmarshal([]byte(invalidJSON), &result)
if err != nil {
// 捕获到解析错误
fmt.Println("JSON解析失败,错误信息:", err)
return
}
fmt.Println("解析结果:", result)
}
json包常见错误类型详解
json包中定义了一些具体的错误类型,我们可以通过类型断言判断错误的具体类型,从而做针对性的处理。常见的错误类型有以下几种:
1. json.SyntaxError
这种错误是JSON语法本身有问题的时候触发的,比如缺少引号、括号不匹配、键没有用双引号包裹等。我们可以通过类型断言判断是否为该错误,还能获取到错误发生的偏移量。
package main
import (
"encoding/json"
"fmt"
)
func main() {
invalidJSON := `{"name": "test", age: 18}` // age没有双引号,语法错误
var result map[string]interface{}
err := json.Unmarshal([]byte(invalidJSON), &result)
if err != nil {
// 判断是否为语法错误类型
if syntaxErr, ok := err.(*json.SyntaxError); ok {
fmt.Printf("JSON语法错误,错误偏移量:%d,错误信息:%sn", syntaxErr.Offset, syntaxErr.Error())
} else {
fmt.Println("其他错误:", err)
}
return
}
}
2. json.UnmarshalTypeError
这种错误发生在目标类型和JSON数据的实际类型不匹配的时候,比如JSON里某个字段是字符串,但是我们解析到int类型的字段中,就会触发这个错误。错误中会包含期望的类型、实际的类型以及对应的字段路径。
package main
import (
"encoding/json"
"fmt"
)
type User struct {
Name string `json:"name"`
Age int `json:"age"`
}
func main() {
// age字段是字符串,和目标int类型不匹配
jsonStr := `{"name": "张三", "age": "二十"}`
var user User
err := json.Unmarshal([]byte(jsonStr), &user)
if err != nil {
if typeErr, ok := err.(*json.UnmarshalTypeError); ok {
fmt.Printf("类型不匹配错误,字段:%s,期望类型:%v,实际类型:%v,错误信息:%sn",
typeErr.Field, typeErr.Type, typeErr.Value, typeErr.Error())
} else {
fmt.Println("其他错误:", err)
}
return
}
fmt.Println("解析结果:", user)
}
3. json.UnsupportedTypeError
当我们尝试解析到json包不支持的类型时,会触发这个错误。比如目标结构体中包含函数类型的字段,json包无法处理这种类型,就会返回该错误。
package main
import (
"encoding/json"
"fmt"
)
type Data struct {
Fn func() // 函数类型,json包不支持
}
func main() {
jsonStr := `{"fn": null}`
var data Data
err := json.Unmarshal([]byte(jsonStr), &data)
if err != nil {
if unsupportedErr, ok := err.(*json.UnsupportedTypeError); ok {
fmt.Printf("不支持的类型错误,类型:%v,错误信息:%sn", unsupportedErr.Type, unsupportedErr.Error())
} else {
fmt.Println("其他错误:", err)
}
return
}
}
4. json.UnsupportedValueError
这种错误通常出现在尝试序列化不支持的值的时候,比如序列化一个通道类型的值,或者解析时遇到不支持的值场景,错误信息会说明具体的不支持原因。
错误捕获的最佳实践
在实际开发中,我们不需要每次都针对所有错误类型做判断,大部分场景下只需要判断错误是否为nil即可。如果需要对特定错误做特殊处理,再针对性地做类型断言。另外,解析前可以先校验JSON字符串的基本格式,减少不必要的错误判断逻辑。
如果是使用json.Decoder来解析流式的JSON数据,错误捕获方式和json.Unmarshal类似,同样判断Decode方法返回的错误即可:
package main
import (
"encoding/json"
"fmt"
"strings"
)
func main() {
// 模拟流式JSON数据
jsonStream := `{"name": "李四", "age": 20}`
decoder := json.NewDecoder(strings.NewReader(jsonStream))
var user map[string]interface{}
err := decoder.Decode(&user)
if err != nil {
fmt.Println("流式解析错误:", err)
return
}
fmt.Println("解析结果:", user)
}
掌握这些错误捕获方法和错误类型的特点,能让我们在处理Golang JSON解析相关逻辑时更加得心应手,也能让代码的异常处理更加完善,减少线上问题的排查成本。