在Go中处理JSON Post请求

时间:2013-03-28 01:16:07

标签: json go

所以我有以下,看起来非常h​​acky,我一直在想自己Go有比这更好的设计库,但是我找不到Go处理JSON数据的POST请求的例子。它们都是POST形式。

以下是一个示例请求:curl -X POST -d "{\"test\": \"that\"}" http://localhost:8082/test

这是代码,嵌入了日志:

package main

import (
    "encoding/json"
    "log"
    "net/http"
)

type test_struct struct {
    Test string
}

func test(rw http.ResponseWriter, req *http.Request) {
    req.ParseForm()
    log.Println(req.Form)
    //LOG: map[{"test": "that"}:[]]
    var t test_struct
    for key, _ := range req.Form {
        log.Println(key)
        //LOG: {"test": "that"}
        err := json.Unmarshal([]byte(key), &t)
        if err != nil {
            log.Println(err.Error())
        }
    }
    log.Println(t.Test)
    //LOG: that
}

func main() {
    http.HandleFunc("/test", test)
    log.Fatal(http.ListenAndServe(":8082", nil))
}

必须有更好的方法,对吧?我很难找到最好的做法。

(Go也被称为搜索引擎的Golang,这里提到其他人可以找到它。)

7 个答案:

答案 0 :(得分:333)

请使用json.Decoder代替json.Unmarshal

func test(rw http.ResponseWriter, req *http.Request) {
    decoder := json.NewDecoder(req.Body)
    var t test_struct
    err := decoder.Decode(&t)
    if err != nil {
        panic(err)
    }
    log.Println(t.Test)
}

答案 1 :(得分:70)

您需要阅读req.BodyParseForm方法正在从req.Body读取,然后以标准HTTP编码格式对其进行解析。你想要的是读取正文并以JSON格式解析它。

这是您的代码更新。

package main

import (
    "encoding/json"
    "log"
    "net/http"
    "io/ioutil"
)

type test_struct struct {
    Test string
}

func test(rw http.ResponseWriter, req *http.Request) {
    body, err := ioutil.ReadAll(req.Body)
    if err != nil {
        panic(err)
    }
    log.Println(string(body))
    var t test_struct
    err = json.Unmarshal(body, &t)
    if err != nil {
        panic(err)
    }
    log.Println(t.Test)
}

func main() {
    http.HandleFunc("/test", test)
    log.Fatal(http.ListenAndServe(":8082", nil))
}

答案 2 :(得分:39)

我对这个确切的问题感到很疯狂。我的JSON Marshaller和Unmarshaller没有填充我的Go结构。然后我在https://eager.io/blog/go-and-json找到了解决方案:

“与Go中的所有结构一样,重要的是要记住,只有具有大写第一个字母的字段才能对外部程序(如JSON Marshaller)可见。”

在那之后,我的Marshaller和Unmarshaller工作得很好!

答案 3 :(得分:16)

我发现文档中的以下示例非常有用(来源here)。

package main

import (
    "encoding/json"
    "fmt"
    "io"
    "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))
    for {
        var m Message
        if err := dec.Decode(&m); err == io.EOF {
            break
        } else if err != nil {
            log.Fatal(err)
        }
        fmt.Printf("%s: %s\n", m.Name, m.Text)
    }
}

这里的关键是OP正在寻求解码

type test_struct struct {
    Test string
}

...在这种情况下,我们会删除const jsonStream,并将Message结构替换为test_struct

func test(rw http.ResponseWriter, req *http.Request) {
    dec := json.NewDecoder(req.Body)
    for {
        var t test_struct
        if err := dec.Decode(&t); err == io.EOF {
            break
        } else if err != nil {
            log.Fatal(err)
        }
        log.Printf("%s\n", t.Test)
    }
}

更新:我还要补充一点,this post提供了一些关于使用JSON进行响应的精彩数据。作者解释了struct tags,我不知道。

由于JSON通常不像{"Test": "test", "SomeKey": "SomeVal"},而是{"test": "test", "somekey": "some value"},因此您可以像这样重构结构:

type test_struct struct {
    Test string `json:"test"`
    SomeKey string `json:"some-key"`
}

...现在你的处理程序将使用" some-key"解析JSON。而不是" SomeKey" (你将在内部使用)。

答案 4 :(得分:10)

$scope.submit = function() { $scope.upload($scope.file); }; $scope.upload = function (file) { console.log(file); Upload.upload({ url: 'http://192.168.99.154/ComputerLog/backup', method: 'POST', data: {file: file} }).then(function (resp) { console.log('Success ' + resp.config.data.file.name + 'uploaded. Response: ' + resp.data); }, function (resp) { console.log('Error status: ' + resp.status); }, function (evt) { var progressPercentage = parseInt(100.0 * evt.loaded / evt.total); console.log('progress: ' + progressPercentage + '% ' + evt.config.data.file.name); }); }; 优于json.Decoder的两个原因-在2013年最流行的答案中没有解决:

  1. 2018年2月,json.Unmarshal引入了一种新方法json.Decoder.DisallowUnknownFields(),该方法解决了检测不需要的JSON输入的问题
  2. go 1.10已经是req.Body。如果流是一个10MB的无效JSON块,则读取其全部内容然后执行io.Reader会浪费资源。使用json.Unmarshal解析请求正文,因为它遇到 streams ,如果遇到无效的JSON,将触发早期解析错误。首选实时处理I / O流。

解决一些有关检测错误用户输入的用户评论:

要强制执行必填字段和其他卫生检查,请尝试:

json.Decoder

Playground

典型输出:

d := json.NewDecoder(req.Body)
d.DisallowUnknownFields() // catch unwanted fields

// anonymous struct type: handy for one-time use
t := struct {
    Test *string `json:"test"` // pointer so we can test for field absence
}{}

err := d.Decode(&t)
if err != nil {
    // bad JSON or unrecognized json field
    http.Error(rw, err.Error(), http.StatusBadRequest)
    return
}

if t.Test == nil {
    http.Error(rw, "missing field 'test' from JSON object", http.StatusBadRequest)
    return
}

// optional extra check
if d.More() {
    http.Error(rw, "extraneous data after JSON object", http.StatusBadRequest)
    return
}

// got the input we expected: no more, no less
log.Println(*t.Test)

答案 5 :(得分:2)

return <video src={"https:" + myUrl}></video>

答案 6 :(得分:0)

我喜欢在本地定义自定义结构。所以:

// my handler func
func addImage(w http.ResponseWriter, r *http.Request) {

    // define custom type
    type Input struct {
        Url        string  `json:"url"`
        Name       string  `json:"name"`
        Priority   int8    `json:"priority"`
    }

    // define a var 
    var input Input

    // decode input or return error
    err := json.NewDecoder(r.Body).Decode(&input)
    if err != nil {
        w.WriteHeader(400)
        fmt.Fprintf(w, "Decode error! please check your JSON formating.")
        return
    }

    // print user inputs
    fmt.Fprintf(w, "Inputed name: %s", input.Name)

}