gpt4 book ai didi

json - 在 HTTP 响应中处理接口(interface)的最佳方式

转载 作者:IT王子 更新时间:2023-10-29 02:02:08 25 4
gpt4 key购买 nike

我正在使用以这种方式格式化其响应的 API:

{
"err": 0,
"data": **Other json structure**
}

我现在获得响应的方式是将响应放入这样的结构中:

type Response struct {
Err int `json:"err"`
Data interface{} `json:"data"`
}

然后我在收到回复后执行此操作

jsonbytes, _ := json.Marshal(resp.Data)
json.Unmarshal(jsonBytes, &dataStruct)

我只是忽略了这个例子的错误。
当我知道数据应该是什么样子以及它应该是什么类型时,我正在编码和解码对我来说似乎有点奇怪。

是否有我没有看到的更简单的解决方案,或者这是正常的做法?

编辑:我应该提一下,响应对象中的数据属性可能会根据我正在执行的 API 调用而有所不同。

最佳答案

JSON 解码器使用反射来查看它要解码到的类型。将未初始化的 interface{} 作为解码数据的目的地,JSON object 被解码为 map[string]interface{}( example in playground ).

这里有一些想法。

选项A

如果您知道数据类型,则可以为每种类型定义一个新的响应结构。示例:

type FooResponse struct {
Err int `json:"err"`
Data Foo `json:"data"`
}

type Foo struct {
FooField string `json:"foofield"`
}

type BarResponse struct {
Err int `json:"err"`
Data Bar `json:"data"`
}

type Bar struct {
BarField string `json:"barfield"`
}

选项B

如果您更喜欢单个 Response 结构而不是每个类型一个,您可以告诉 JSON 解码器避免解码 data 字段,直到稍后通过使用json.RawMessage 数据类型:

package main

import (
"encoding/json"
"fmt"
"log"
)

type Response struct {
Err int `json:"err"`
Data json.RawMessage `json:"data"`
}

type Foo struct {
FooField string `json:"foofield"`
}

type Bar struct {
BarField string `json:"barfield"`
}

func main() {
fooRespJSON := []byte(`{"data":{"foofield":"foo value"}}`)
barRespJSON := []byte(`{"data":{"barfield":"bar value"}}`)

var (
resp Response
foo Foo
bar Bar
)

// Foo
if err := json.Unmarshal(fooRespJSON, &resp); err != nil {
log.Fatal(err)
}
if err := json.Unmarshal(resp.Data, &foo); err != nil {
log.Fatal(err)
}
fmt.Println("foo:", foo)

// Bar
if err := json.Unmarshal(barRespJSON, &resp); err != nil {
log.Fatal(err)
}
if err := json.Unmarshal(resp.Data, &bar); err != nil {
log.Fatal(err)
}
fmt.Println("bar:", bar)
}

输出:

foo: {foo value}
bar: {bar value}

https://play.golang.org/p/Y7D4uhaC4a8

选项C

正如@mkopriva 在对该问题的评论中指出的那样,第三种选择是使用 interface{} 作为中间数据类型并将其预初始化为已知数据类型。

重点在于中介这个词——当然最好避免传递 interface{} ( Rob Pike's Go Proverbs )。这里的用例是允许使用任何数据类型而不需要多个不同的 Response 类型。避免暴露接口(interface){}的一种方法是完全包装响应,仅暴露数据和错误:

package main

import (
"encoding/json"
"fmt"
"log"
)

type Foo struct {
FooField string `json:"foofield"`
}

type Bar struct {
BarField string `json:"barfield"`
}

type Error struct {
Code int
}

func (e *Error) Error() string {
return fmt.Sprintf("error code %d", e.Code)
}

func unmarshalResponse(data []byte, v interface{}) error {
resp := struct {
Err int `json:"err"`
Data interface{} `json:"data"`
}{Data: v}

if err := json.Unmarshal(data, &resp); err != nil {
return err
}

if resp.Err != 0 {
return &Error{Code: resp.Err}
}

return nil
}

func main() {
fooRespJSON := []byte(`{"data":{"foofield":"foo value"}}`)
barRespJSON := []byte(`{"data":{"barfield":"bar value"}}`)
errRespJSON := []byte(`{"err": 123}`)

// Foo
var foo Foo
if err := unmarshalResponse(fooRespJSON, &foo); err != nil {
log.Fatal(err)
}
fmt.Println("foo:", foo)

// Bar
var bar Bar
if err := unmarshalResponse(barRespJSON, &bar); err != nil {
log.Fatal(err)
}
fmt.Println("bar:", bar)

// Error response
var v interface{}
if err := unmarshalResponse(errRespJSON, &v); err != nil {
log.Fatal(err)
}
}

输出:

foo: {foo value}
bar: {bar value}
2009/11/10 23:00:00 error code 123

https://play.golang.org/p/5SVfQGwS-Wy

关于json - 在 HTTP 响应中处理接口(interface)的最佳方式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49611868/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com