Dus ik heb het volgende, dat ongelooflijk gehackt lijkt, en ik heb bij mezelf gedacht dat Go beter ontworpen bibliotheken heeft dan dit, maar ik kan geen voorbeeld vinden van Go die een POST-verzoek van JSON-gegevens afhandelt. Het zijn allemaal POST’s.
Hier is een voorbeeldverzoek: curl -X POST -d "{\"test\": \"that\"}" http://localhost:8082/test
En hier is de code, met de logs ingesloten:
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))
}
Er moet toch een betere manier zijn? Ik ben gewoon stumped in het vinden van wat de beste praktijk zou kunnen zijn.
(Go staat bij de zoekmachines ook bekend als Golang en wordt hier vermeld zodat anderen het kunnen vinden.)
Antwoord 1, autoriteit 100%
Gebruik a.u.b. json.Decoder
in plaats van 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)
}
Antwoord 2, autoriteit 22%
Je moet lezen uit req.Body
. De methode ParseForm
leest van de req.Body
en analyseert deze vervolgens in standaard HTTP-gecodeerd formaat. Wat u wilt, is de hoofdtekst lezen en ontleden in JSON-indeling.
Hier is uw code bijgewerkt.
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))
}
Antwoord 3, autoriteit 16%
Ik maakte mezelf gek met dit exacte probleem. Mijn JSON Marshaller en Unmarshaller vulden mijn Go-struct niet. Toen vond ik de oplossing op https://eager.io/blog/go-and-json:
“Zoals met alle structs in Go, is het alleen belangrijk om dat te onthouden
velden met een hoofdletter zijn zichtbaar voor externe programma’s
zoals de JSON Marshaller.”
Daarna werkten mijn Marshaller en Unmarshaller perfect!
Antwoord 4, autoriteit 16%
Er zijn twee redenen waarom json.Decoder
de voorkeur verdient boven json.Unmarshal
– die niet aan bod komen in het meest populaire antwoord uit 2013:
- Februari 2018,
go 1.10
introduceerde een nieuwe methode json .Decoder.DisallowUnknownFields()die de bezorgdheid wegneemt van het detecteren van ongewenste JSON-invoer req.Body
is al eenio.Reader
. Het lezen van de volledige inhoud en het uitvoeren vanjson.Unmarshal
verspilt bronnen als de stream bijvoorbeeld een blok van 10 MB ongeldige JSON was. Het ontleden van de aanvraagtekst, metjson.Decoder
, terwijl het stroomtbinnen zou een vroege parseerfout veroorzaken als ongeldige JSON werd aangetroffen. Het verwerken van I/O-stromen in realtime heeft de voorkeur go-way.
het aanpakken van enkele van de opmerkingen van de gebruiker over het detecteren van slechte gebruikersinvoer:
Om verplichte velden af te dwingen, en andere sanitaire controles, probeer dan:
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)
Typische output:
$ curl -X POST -d "{}" http://localhost:8082/strict_test
expected json field 'test'
$ curl -X POST -d "{\"Test\":\"maybe?\",\"Unwanted\":\"1\"}" http://localhost:8082/strict_test
json: unknown field "Unwanted"
$ curl -X POST -d "{\"Test\":\"oops\"}g4rB4g3@#$%^&*" http://localhost:8082/strict_test
extraneous data after JSON
$ curl -X POST -d "{\"Test\":\"Works\"}" http://localhost:8082/strict_test
log: 2019/03/07 16:03:13 Works
Antwoord 5, Autoriteit 5%
Ik vond het volgende voorbeeld van de Docs echt behulpzaam (bron hier ).
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)
}
}
De sleutel hier is dat het OP was om te decoderen
type test_struct struct {
Test string
}
… In welk geval zouden we de const jsonStream
vallen en de Message
struct gebruiken met de 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)
}
}
Bijwerken : Ik zou ook toevoegen dat deze na biedt een aantal goede gegevens over het reageren met JSON ook. De auteur legt struct tags
, die ik niet bewust van was.
Sinds JSON niet normaal uitzien als {"Test": "test", "SomeKey": "SomeVal"}
, maar {"test": "test", "somekey": "some value"}
, kunt u uw structuur herstructureren als volgt uit:
type test_struct struct {
Test string `json:"test"`
SomeKey string `json:"some-key"`
}
… en nu handler zal ontleden JSON met behulp van “sommige-key” in tegenstelling tot “SomeKey” (die u intern zal worden gebruikt).
Antwoord 6
type test struct {
Test string `json:"test"`
}
func test(w http.ResponseWriter, req *http.Request) {
var t test_struct
body, _ := ioutil.ReadAll(req.Body)
json.Unmarshal(body, &t)
fmt.Println(t)
}
Antwoord 7
Ik vind het leuk om lokaal aangepaste structuren te definiëren. Dus:
// 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)
}