去处理JSON响应和请求

时间:2019-01-13 22:40:55

标签: json go struct

我对Go来说还比较陌生,尽管到目前为止我对大部分内容都掌握得很好,但是我仍然无法确切地知道应该如何处理JSON。

因此,假设我在前端有一个访问令牌。我想通过它,并向API提出请求以对其进行验证。

这是传递给后端的json:

{
   "accessToken": "xxxxxx"
}


type test_struct struct {
    AccessToken string `json:"accessToken"`
}

func validateFacebookLogin(w http.ResponseWriter, r *http.Request) {
    decoder := json.NewDecoder(r.Body)
    var t test_struct
    err := decoder.Decode(&t)
    if err != nil {
        panic(err)
    }
    tokenCheck := "xxxxxxxxx|xxxxxxxxxxxxxxxxxxxxxxxxxxx"
    req, err := http.NewRequest("GET", "https://graph.facebook.com/debug_token", nil)
    if err != nil {
        log.Print(err)
        os.Exit(1)
    }
    q := req.URL.Query()

    q.Add("input_token", t.AccessToken)
    q.Add("access_token", tokenCheck)
    req.URL.RawQuery = q.Encode()
    resp, err := http.Get(req.URL.String())
    defer resp.Body.Close()
    bodyBytes, _ := ioutil.ReadAll(resp.Body)
    bodyString := string(bodyBytes)
    fmt.Println(bodyString);
    json.NewEncoder(w).Encode(map[string]string{"message": "FINE"})
    json.NewEncoder(w).Encode(resp)

}

我能找到的所有文档似乎都表明应该为所有JSON响应/请求创建一个结构(除非我误会了)。这样不方便吗?如果我的嵌套JSON响应异常大怎么办?我必须创建COMPLETE响应的结构吗?

我在ioutil上使用的方法是不好的做法吗?在哪里我可以传回整个字符串表示形式并设法在前端对其进行解码?

我想我的主要问题是,何时应将JSON分配给结构?什么是最佳做法?如果我打算立即将响应返回到前端,那有什么意义吗?

假设我确实想在后端维护数据,那么是否有任何“更好”的方法来处理较大的响应?

1 个答案:

答案 0 :(得分:2)

在大多数情况下,您只需要简单地利用json.Unmarshal。该用例在大多数情况下都有效:

var myClient = &http.Client{Timeout: 10 * time.Second}

func getJson(url string, target interface{}) error {
    r, err := myClient.Get(url)
    if err != nil {
        return err
    }
    defer r.Body.Close()

    return json.NewDecoder(r.Body).Decode(target)
}

foo := Foo{}
getJson("http://example.com", &foo2)
fmt.Printf("%+v\n", foo)

但是,如果您真正使用的是大型数据集,请查看https://golang.org/pkg/encoding/json/#example_Decoder_Decode_stream

package main

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

func main() {
    const jsonStream = `
    [
        {"Name": "Ed", "Text": "Knock knock."},
        {"Name": "Sam", "Text": "Who's there?"},
        {"Name": "Ed", "Text": "Go fmt."},
        {"Name": "Sam", "Text": "Go fmt who?"},
        {"Name": "Ed", "Text": "Go fmt yourself!"}
    ]
`
    type Message struct {
        Name, Text string
    }
    dec := json.NewDecoder(strings.NewReader(jsonStream))

    // read open bracket
    t, err := dec.Token()
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("%T: %v\n", t, t)

    // while the array contains values
    for dec.More() {
        var m Message
        // decode an array value (Message)
        err := dec.Decode(&m)
        if err != nil {
            log.Fatal(err)
        }

        fmt.Printf("%v: %v\n", m.Name, m.Text)
    }

    // read closing bracket
    t, err = dec.Token()
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("%T: %v\n", t, t)

}

这将使您以更高效的内存工作方式。

更多关于您的问题:

  1. 我是否必须解组完整的响应结构? -并非如此,您只需要定义要在结构中使用的内容,其余的将被忽略
  2. 您做对了吗? -您没有做任何天生的错误?

如果我没有回答,请告诉我。

编辑:对于ioutil.ReadAll的用法-一般来说,您需要解组为一个结构,以便实际上可以使用数据,并且通过您的结构从类型安全中受益。如果您只需要字符串,那么您在做什么就可以了,但是通常不是这种情况。