Golang中Json.unmarshal解析未知响应体时如何处理
Golang中Json.unmarshal解析未知响应体时如何处理 我调用一个API,而同一个API会返回两种不同的响应结构(与文档描述不符……API Reference — Kea 2.0.1 documentation)
[ { "result": 0, "text": "Configuration successful." } ]
我定义了以下结构体来解析响应体:
type firstResponse []struct {
Result int `json:"result"`
Text string `json:"text"`
}
和
{ "result": 400, "text": "Bad Request" }
我也定义了相应的结构体来解析响应体:
type secondResponse struct {
Result int `json:"result"`
Text string `json:"text"`
}
处理这种情况的最佳方式是什么?如果能提供一个简单的答案,为我指明正确的方向,我将不胜感激。
此外,当我需要访问这些数据时,我还必须知道我使用了哪种结构体类型。
更多关于Golang中Json.unmarshal解析未知响应体时如何处理的实战教程也可以访问 https://www.itying.com/category-94-b0.html
好的,我会在IRC上向他们提一下这件事。
更多关于Golang中Json.unmarshal解析未知响应体时如何处理的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
啊,是的,幸运的是,“错误请求”会返回400状态码,而成功请求则返回200,这样我就能保持代码的整洁。
顺便提一下……API的代码返回了两种不同类型的结构体,这会不会是一个bug呢?
检查HTTP状态码。如果是400,你很可能在响应体中得到了第二个JSON。
我还没有查看你链接的文档,但可悲的是,许多API文档只描述了“成功”的情况,错误处理通常只是在一个段落中简要描述,将所有可能的情况合并成一句话和一个几乎不包含实际价值的JSON对象……
再次,你是否检查了响应的HTTP状态码?如果它与JSON中的代码相符,那么基于此进行分支判断应该很容易。
另一种方法是先将其解组到 interface{} 中,然后使用类型开关来区分顶层对象和顶层列表。接着再将 interface{} 值转换为结构体。不过,这样代码会非常冗长。
func main() {
fmt.Println("hello world")
}
这取决于它们的文档。
一般来说,API 是无类型的。是人类为二进制数据块赋予了一些语义和句法意义。
它们提供的文档描述了它们那部分的“契约”。
如果它们的做法与文档描述的不同,那么要么是结果错了,要么是文档错了。
我没有也不会阅读链接的文档,因为它内容太多了。
不过正如我已经说过的,“一切顺利”通常作为端点文档的一部分进行描述,而“出现错误”则有自己通用的章节,遗憾的是这部分内容通常非常简略。
感谢您的回答……但我实际面临的问题是处理响应,因为它们是两种不同的结构,我不知道会返回哪一种。
我正在寻找处理它们的方法。我想我可以:
- 使用一系列错误检查来填充正确的结构
- 剥离数组(如果存在),并且有办法做到这一点并将结果放入
secondResponse - 添加一个数组(如果不存在),并且有办法做到这一点并将结果放入
firstResponse - 将响应转换为字符串,添加或移除数组,然后转换为所需的结构
只是想请教是否有更好的方法。 我查阅了 Go 语言的 JSON 文档,但没有发现什么有用的信息。
在Golang中处理JSON响应结构不确定的情况,可以使用以下两种方法:
方法1:使用json.RawMessage进行延迟解析
package main
import (
"encoding/json"
"fmt"
)
// 定义两种可能的结构
type FirstResponse []struct {
Result int `json:"result"`
Text string `json:"text"`
}
type SecondResponse struct {
Result int `json:"result"`
Text string `json:"text"`
}
func parseResponse(data []byte) (interface{}, error) {
// 先尝试解析为数组格式
var firstResp FirstResponse
if err := json.Unmarshal(data, &firstResp); err == nil && len(firstResp) > 0 {
return firstResp, nil
}
// 再尝试解析为对象格式
var secondResp SecondResponse
if err := json.Unmarshal(data, &secondResp); err == nil {
return secondResp, nil
}
return nil, fmt.Errorf("无法解析响应")
}
func main() {
// 测试数据
data1 := []byte(`[ { "result": 0, "text": "Configuration successful." } ]`)
data2 := []byte(`{ "result": 400, "text": "Bad Request" }`)
// 解析响应1
resp1, _ := parseResponse(data1)
switch v := resp1.(type) {
case FirstResponse:
fmt.Printf("类型: FirstResponse, 结果: %v\n", v[0].Text)
case SecondResponse:
fmt.Printf("类型: SecondResponse, 结果: %v\n", v.Text)
}
// 解析响应2
resp2, _ := parseResponse(data2)
switch v := resp2.(type) {
case FirstResponse:
fmt.Printf("类型: FirstResponse, 结果: %v\n", v[0].Text)
case SecondResponse:
fmt.Printf("类型: SecondResponse, 结果: %v\n", v.Text)
}
}
方法2:使用自定义UnmarshalJSON方法
package main
import (
"encoding/json"
"fmt"
)
type UnifiedResponse struct {
IsArray bool
Array []ResponseItem
Single ResponseItem
}
type ResponseItem struct {
Result int `json:"result"`
Text string `json:"text"`
}
func (ur *UnifiedResponse) UnmarshalJSON(data []byte) error {
// 尝试解析为数组
var arr []ResponseItem
if err := json.Unmarshal(data, &arr); err == nil {
ur.IsArray = true
ur.Array = arr
return nil
}
// 尝试解析为单个对象
var single ResponseItem
if err := json.Unmarshal(data, &single); err == nil {
ur.IsArray = false
ur.Single = single
return nil
}
return fmt.Errorf("无法解析JSON")
}
func (ur *UnifiedResponse) GetResult() int {
if ur.IsArray && len(ur.Array) > 0 {
return ur.Array[0].Result
}
return ur.Single.Result
}
func (ur *UnifiedResponse) GetText() string {
if ur.IsArray && len(ur.Array) > 0 {
return ur.Array[0].Text
}
return ur.Single.Text
}
func main() {
data1 := []byte(`[ { "result": 0, "text": "Configuration successful." } ]`)
data2 := []byte(`{ "result": 400, "text": "Bad Request" }`)
var resp1 UnifiedResponse
json.Unmarshal(data1, &resp1)
fmt.Printf("响应1 - 类型: %v, 文本: %s\n", resp1.IsArray, resp1.GetText())
var resp2 UnifiedResponse
json.Unmarshal(data2, &resp2)
fmt.Printf("响应2 - 类型: %v, 文本: %s\n", resp2.IsArray, resp2.GetText())
}
方法3:使用interface{}和类型断言
package main
import (
"encoding/json"
"fmt"
)
func parseAPIResponse(data []byte) {
var result interface{}
json.Unmarshal(data, &result)
switch v := result.(type) {
case []interface{}:
// 数组格式
if len(v) > 0 {
if item, ok := v[0].(map[string]interface{}); ok {
fmt.Printf("数组格式 - Result: %v, Text: %v\n",
item["result"], item["text"])
}
}
case map[string]interface{}:
// 对象格式
fmt.Printf("对象格式 - Result: %v, Text: %v\n",
v["result"], v["text"])
}
}
func main() {
data1 := []byte(`[ { "result": 0, "text": "Configuration successful." } ]`)
data2 := []byte(`{ "result": 400, "text": "Bad Request" }`)
parseAPIResponse(data1)
parseAPIResponse(data2)
}
推荐使用方法2,它提供了类型安全的访问方式,同时保持了代码的清晰性。通过统一的接口访问数据,无需在业务代码中频繁进行类型判断。

