本文紧接 Go 编程 | 连载 28 - Go 与 JSON
二、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 | mapstringinterface{} |
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"`
}
执行上述代码,输出结果如下:
代码语言:javascript复制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 框架
代码语言:javascript复制go get -u github.com/gin-gonic/gin
新建 main.go 文件,添加如下代码:
代码语言:javascript复制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 文件,输入如下代码:
代码语言:javascript复制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("% vn", data)
fmt.Printf("%Tn", data)
}
type Data struct {
Msg string `json:"msg"`
Code int `json:"code"`
}
执行上述代码,输出结果如下:
代码语言:javascript复制&{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