Obsługa żądania JSON Post w Go

Więc mam następujące, co wydaje się niesamowicie hacky, i myślałem sobie, że Go ma lepiej zaprojektowane biblioteki niż to, ale nie mogę znaleźć przykład Go obsługi żądania POST danych JSON. Wszystkie one są formą postów.

Oto przykładowe ZAPYTANIE: curl -X POST -d "{\"test\": \"that\"}" http://localhost:8082/test

A oto kod, z wbudowanymi logami:

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))
}
Musi być lepszy sposób, prawda? Nie mogę znaleźć najlepszej praktyki.

(Go jest również znany jako Golang do wyszukiwarek, i wymienione tutaj, aby inni mogli go znaleźć.)

 185
Author: TomJ, 2013-03-28

4 answers

Proszę użyć json.Decoder zamiast 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)
}
 289
Author: Joe,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-06-20 17:35:10

Musisz czytać z req.Body. Metoda ParseForm jest odczytywana z req.Body, a następnie analizowana w standardowym formacie kodowanym HTTP. To, co chcesz, to odczytać ciało i przetworzyć je w formacie JSON.

Tu masz zaktualizowany kod.
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))
}
 59
Author: Daniel,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-02-06 08:49:24

Doprowadzałem się do szału z tym problemem. Mój JSON Marshaller i Unmarshaller nie wypełniali mojej struktury Go. Następnie znalazłem rozwiązanie w https://eager.io/blog/go-and-json :

" podobnie jak w przypadku wszystkich struktur w Go, ważne jest, aby pamiętać, że tylko pola z pierwszą wielką literą są widoczne dla zewnętrznych programów, takich jak JSON Marshaller."

Po tym, mój Marshaller i Unmarshaller pracował doskonale!

 31
Author: Steve Stilson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-03-15 00:01:24

Poniższy przykład z dokumentów okazał się bardzo pomocny (źródło tutaj).

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)
    }
}

Kluczem jest to, że operacja chciała odkodować

type test_struct struct {
    Test string
}

... W takim przypadku odrzucilibyśmy const jsonStream i zamienilibyśmy Message strukturą na 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)
    }
}

Update : dodam jeszcze, że ten post dostarcza również świetnych danych na temat odpowiedzi z JSON. Autor wyjaśnia struct tags, o czym nie wiedziałem.

Od JSON zazwyczaj nie wygląda jak {"Test": "test", "SomeKey": "SomeVal"}, ale raczej {"test": "test", "somekey": "some value"}, możesz zrestrukturyzować swoją strukturę w następujący sposób:

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

...a teraz twój handler będzie analizował JSON używając "some-key" w przeciwieństwie do "SomeKey" (którego będziesz używał wewnętrznie).

 14
Author: JohnnyCoder,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-09-23 14:26:25