Go 語(yǔ)言怎么處理三方接口返回?cái)?shù)據(jù)?
?1.介紹
在使用 Go 語(yǔ)言調(diào)用三方RESTful接口時(shí),因?yàn)闊o(wú)法直接操作 json 字符串,所以我們需要先將 json 字符串轉(zhuǎn)換為 map 或 struct。
本文我們介紹一下怎么處理三方接口返回?cái)?shù)據(jù)。
2.普通 json
我們先看一下三方接口返回的普通 json。
func main() {
// 三方返回普通 json 字符串
jsonRes := `{
"Id": 1001,
"Name": "frank"
}`
data := new(User)
err := json.Unmarshal([]byte(jsonRes), &data)
if err != nil {
log.Printf("json Unmarshal err:%v\n", err)
return
}
fmt.Printf("data=%+v", data)
}
type User struct {
Id int
Name string
}
輸出結(jié)果:
data=&{Id:1001 Name:frank}
閱讀上面這段代碼,我們構(gòu)造一個(gè)簡(jiǎn)單的 json 字符串,模擬三方接口返回?cái)?shù)據(jù)。
我們使用 Go 標(biāo)準(zhǔn)庫(kù) encoding/json? 的 Unmarshal 函數(shù),可以很容易將 json 數(shù)據(jù)解碼到 struct,從而方便我們讀取返回?cái)?shù)據(jù)。
但是,需要讀者朋友們注意的是,假如三方接口返回?cái)?shù)據(jù)的字段類(lèi)型隨機(jī)變化(比如示例中的 Id? 字段,可能是整型或字符串隨機(jī)返回),我們使用 Unmarshal 函數(shù)解碼時(shí),就有可能會(huì)返回錯(cuò)誤,如下所示:
2022/08/15 14:07:41 json Unmarshal err:json: cannot unmarshal string into Go struct field User.Id of type int
閱讀到這里,我相信已經(jīng)有讀者朋友們想到,可以把返回?cái)?shù)據(jù)解碼到 map[string]interface{} 類(lèi)型的變量中。
示例代碼:
func main() {
// 三方返回普通 json 字符串
jsonRes := `{
"Id": 1001,
"Name": "frank"
}`
data2 := make(map[string]interface{})
err := json.Unmarshal([]byte(jsonRes), &data2)
if err != nil {
log.Printf("json Unmarshal err:%v\n", err)
return
}
fmt.Printf("data2=%+v", data2)
}
輸出結(jié)果:
data2=map[Id:1001 Name:frank]
閱讀上面示例代碼,我們可以通過(guò)將返回?cái)?shù)據(jù)解碼到 map[string]interface{} 類(lèi)型的變量中,從而解決三方接口返回?cái)?shù)據(jù)的字段類(lèi)型不固定的問(wèn)題。
普通 json 使用該方式處理確實(shí)可行,但是如果嵌套 json,也可以這么處理,但是讀取嵌套 json 的子字段就不那么方便了。
3.嵌套 json
我們?cè)贅?gòu)造一個(gè)三方接口返回?cái)?shù)據(jù)是嵌套 json 的變量。
func main() {
// 三方返回嵌套 json 字符串
jsonRes := `{
"Id": 1001,
"Name": "frank",
"Details": {
"Gender": "man",
"Age": 18,
"Phone": "13800138000",
"address": "Beijing"
}
}`
data := new(User)
err := json.Unmarshal([]byte(jsonRes), &data)
if err != nil {
log.Printf("json Unmarshal err:%v\n", err)
return
}
fmt.Printf("data=%+v", data)
}
type User struct {
Id int
Name string
Details Details
}
type Details struct {
Gender string
Age int
Phone string
Address string
}
輸出結(jié)果:
data=&{Id:1001 Name:frank Details:{Gender:man Age:18 Phone:13800138000 Address:Beijing}}
閱讀上面這段代碼,我們構(gòu)造一個(gè)嵌套 json,使用 Unmarshal 函數(shù)解碼到 struct 中。
但是,如果返回?cái)?shù)據(jù)中的 Age? 字段是字符串類(lèi)型,我們使用 Unmarshal 函數(shù)解碼時(shí),就會(huì)返回以下錯(cuò)誤:
2022/08/15 17:33:08 json Unmarshal err:json: cannot unmarshal string into Go struct field Details.Details.Age of type int
雖然,我們可以使用普通 json 中的處理方式,將返回?cái)?shù)據(jù)解碼到 map[string]interface{} 類(lèi)型的變量中。但是,如果我們想要讀取內(nèi)嵌 json 中的子字段,就讀取不到了。
怎么解決這個(gè)問(wèn)題呢?我們可以借助三方庫(kù) mapstructure?,使用該三方庫(kù)的 Decode? 函數(shù)替代 Go 標(biāo)準(zhǔn)庫(kù) encoding/json? 的 Unmarshal 函數(shù)。
示例代碼:
func main() {
// 三方返回嵌套 json 字符串
jsonRes := `{
"Id": 1001,
"Name": "frank",
"Details": {
"Gender": "man",
"Age": "18",
"Phone": "13800138000",
"address": "Beijing"
}
}`
tmpData := make(map[string]interface{})
err := json.Unmarshal([]byte(jsonRes), &tmpData)
if err != nil {
log.Printf("json Unmarshal err:%v\n", err)
return
}
data2 := new(User)
err = mapstructure.Decode(tmpData, data2)
if err != nil {
log.Printf("decode err:%v\n", err)
return
}
fmt.Printf("data2=%+v\n", data2)
fmt.Printf("age=%v\n", data2.Details.Age)
}
type User struct {
Id int
Name string
Details Details
}
type Details struct {
Gender string
Age interface{}
Phone string
Address string
}
輸出結(jié)果:
data2=&{Id:1001 Name:frank Details:{Gender:man Age:18 Phone:13800138000 Address:Beijing}}
age=18
閱讀上面這段代碼,我們將嵌套 struct 的 Age? 字段定義為 interface{}? 類(lèi)型,首先,我們使用 Go 標(biāo)準(zhǔn)庫(kù)的 Unmarshal? 函數(shù)將返回?cái)?shù)據(jù)解碼到 map[string]interface{} 類(lèi)型的變量中。
然后使用三方庫(kù) mapstructure? 的 Decode? 函數(shù),將 map[string]interface{} 類(lèi)型的變量中的數(shù)據(jù)解碼到 struct 中,從而實(shí)現(xiàn)我們可以讀取內(nèi)嵌 json 中的子字段。
三方庫(kù) mapstructure 還有很多其他好用的功能,感興趣的讀者朋友們可以閱讀官方文檔了解更多內(nèi)容。
4.總結(jié)
本文我們主要介紹怎么處理三方接口返回?cái)?shù)據(jù),其中包含普通 json 和嵌套 json,在處理嵌套 json 的內(nèi)容中,我們介紹了三方庫(kù) mapstructure 的簡(jiǎn)單使用方式。