如何在Go语言中获取JSON响应中的key3数据?
问题描述
我发起了一个JSON请求,代码如下:
req, err := http.NewRequest("GET", myPath, nil) if err != nil { panic(err) } resp, err := http.DefaultClient.Do(req) if err != nil { panic(err) } defer resp.Body.Close() var j map[string]interface{} err = json.NewDecoder(resp.Body).Decode(&j) if err != nil { panic(err) }
此时返回的是map[string]interface{}类型的数据,但JSON的实际结构为:
{ "key1": "string", "key2": "string", "key3": [ { "key1": "string", "key2": 123, "key3": ["str1", "str2"] }, { "key1": "string", "key2": 456, "key3": ["str3", "str4"] }, ...更多元素 ] }
我想获取其中的key3数据,尝试遍历map时遇到瓶颈:
for key, value := range j { if key == "key3" { // 不知道怎么继续处理 } }
我也曾尝试将JSON响应反序列化为结构体,但出现错误:
type key3Struct struct { key1 string key2 string key3 []string } type ResponseStruct struct { key1 string key2 string key3 []key3Struct } // 尝试1 j = ResponseStruct{} json.NewDecoder(resp.Body).Decode(&j) ==> 错误:无法将map[string]interface{}转换为ResponseStruct{} // 尝试2 json.Unmarshal(resp.Body, &j) ==> 结果是[ {} ],没有数据
请问如何正确获取JSON响应中的key3数据?
解决方案
方法一:直接解析map[string]interface{}
如果坚持使用map[string]interface{},需要通过类型断言将interface{}转换为具体类型,步骤如下:
for key, value := range j { if key == "key3" { // 先断言为[]interface{}(JSON数组对应Go的[]interface{}) key3Items, ok := value.([]interface{}) if !ok { panic("key3不是数组类型") } // 遍历数组中的每个元素 for _, item := range key3Items { // 将元素断言为map[string]interface{}(JSON对象对应Go的map) itemMap, ok := item.(map[string]interface{}) if !ok { panic("key3中的元素不是对象类型") } // 提取各个字段,注意类型匹配: // JSON字符串对应string,JSON数字默认解析为float64(需要转成int),JSON数组对应[]interface{} key1 := itemMap["key1"].(string) key2 := int(itemMap["key2"].(float64)) // 转换为int key3Raw := itemMap["key3"].([]interface{}) // 将[]interface{}转为[]string key3 := make([]string, len(key3Raw)) for i, s := range key3Raw { key3[i] = s.(string) } // 这里可以使用提取出的key1、key2、key3 fmt.Println(key1, key2, key3) } } }
方法二:使用结构体反序列化(推荐)
这种方法更简洁、类型安全,你之前的错误主要有三个:
- 结构体字段首字母小写,无法被
encoding/json包访问(Go仅导出首字母大写的字段) - 字段类型不匹配(JSON中
key2是int,你定义为string) - 重复读取
resp.Body(第一次Decode后,Body的游标已经到末尾,第二次读取无数据)
修正后的结构体
// 定义key3数组中的元素结构体 type Key3Item struct { Key1 string `json:"key1"` // json标签指定JSON中的键名 Key2 int `json:"key2"` // 匹配JSON中的int类型 Key3 []string `json:"key3"` } // 定义整个响应的结构体 type Response struct { Key1 string `json:"key1"` Key2 string `json:"key2"` Key3 []Key3Item `json:"key3"` }
正确的反序列化代码
req, err := http.NewRequest("GET", myPath, nil) if err != nil { panic(err) } resp, err := http.DefaultClient.Do(req) if err != nil { panic(err) } defer resp.Body.Close() // 声明结构体变量,不要复用之前的map类型变量j var respData Response err = json.NewDecoder(resp.Body).Decode(&respData) if err != nil { panic(err) } // 直接通过respData.Key3获取数据 for _, item := range respData.Key3 { fmt.Println(item.Key1, item.Key2, item.Key3) }
内容的提问来源于stack exchange,提问作者Aria Lopez
相关产品推荐
相关产品推荐

