二、Go 与 JSON 的格式映射
在序列化和反序列化时需考虑 JavaScript 和 Go 表示数据类型的方式,Go 是静态强类型语言,JavaScript 是动态弱类型语言。
Go 中声明变量是需要声明数据类型的,即使不声明数据类型 Go 也会在编译器自动判断数据类型,而 JavaScript 则是在运行时才会判断数据类型。 JSON 的数据格式与 JavaScript 相同,JSON 可使用的格式有如下几种:
- Boolean
- Number
- String
- Array
- Object
- Null
但是这些数据类型不会自动映射到 Go 中的数据类型,需要通过 encoding/json
包执行显示的类型转换,JSON 和 Go 中数据类型之间的对应关系如下:
JSON 类型 | Go 类型 |
String | string |
Boolean | bool |
Number | float64 |
Array | []interface{} |
Object | map[string]interface{} |
Null | nil |
package main import ( "encoding/json" "fmt" "log" ) //noinspection ALL func main() { jsonString := `{"name": "stark", "is_vip": "true"}` u := User{} err := json.Unmarshal([]byte(jsonString), &u) if err != nil { log.Fatal(err) } fmt.Println(u) } type User struct { Name string `json:"name"` IsVip bool `json:"is_vip"` } 复制代码
执行上述代码,输出结果如下:
2022/09/01 11:41:45 json: cannot unmarshal string into Go struct field User.is_vip of type bool 复制代码
上述代码反序列化过程中, Go 会将字符串格式的 true 转换为 bool 类型的 true,因此转换失败导致程序停止。
在进行反序列化时要注意 JavaScript 和 Go 之间的类型对应关系,如果转换时类型不对应则会导致错误。
三、处理 HTTP 收到的 JSON 格式数据
在 Go 语言中通过 HTTP 请求收到的 JSON 数据是以流的形式接收的,既不是字符串也不是字节切片,因此需要通过 encoding/json
标准库中的另一个函数 New.Decoder
来进行解码。
我们通过 Gin 框架快速创建一个返回 JSON 格式的 API,使用 net/http
调用这个 API 获取到 JSON 数据,然后将 JSON 数据转换成结构体实例化对象。
首先新建一个 gin-quickstart 项目,然后通过命令行安装 Gin 框架
go get -u github.com/gin-gonic/gin 复制代码
新建 main.go 文件,添加如下代码:
package main // 导入 gin 依赖 //noinspection ALL import ( "github.com/gin-gonic/gin" "net/http" ) //noinspection ALL func main(){ // 创建路由 engine r := gin.Default() // 创建路由,绑定 handler 函数 r.GET("/json", ResponseJsonHandler) // 启动,绑定端口 r.Run(":8080") } func ResponseJsonHandler (c *gin.Context) { d := Data{ Msg: "你好 JSON", Code: 20000, } c.JSON(http.StatusOK, d) } type Data struct { Msg string `json:"msg"` Code int `json:"code"` } 复制代码
运行 main.go 文件,此时我们就已经搭建了一个 HTTP 服务器,在浏览器中访问 http://localhost:8080/json 可以获取如下响应
接着我们另外一个项目中新建一个 Go 文件,输入如下代码:
package main //noinspection ALL import ( "encoding/json" "fmt" "log" "net/http" ) //noinspection ALL func main() { data := Data{} // 访问 /json API res, err := http.Get("http://localhost:8080/json") if err != nil { log.Fatal(err) } fmt.Println(res) defer res.Body.Close() // 处理 JSON 流,将其数据赋值到一个结构体实例化对象 data 上 err = json.NewDecoder(res.Body).Decode(&data) if err != nil { log.Fatal(err) } fmt.Printf("%+v\n", data) fmt.Printf("%T\n", data) } type Data struct { Msg string `json:"msg"` Code int `json:"code"` } 复制代码
执行上述代码,输出结果如下:
&{200 OK 200 HTTP/1.1 1 1 map[Content-Length:[34] Content-Type:[application/json; charset=utf-8] Date:[Thu, 01 Sep 2022 17:29:25 GMT]] 0xc00015e400 34 [] false false map[] 0xc00017e000 <nil>} {Msg:你好 JSON Code:20000} main.Data