2013-03-28 19 views
166

Quindi ho il seguente, che sembra incredibilmente hacky, e ho pensato a me stesso che Go ha librerie progettate meglio di così, ma non riesco a trovare un esempio di Go che gestisce un POST richiesta di dati JSON. Sono tutti moduli POST.Gestione di JSON Post Request in Go

Ecco un esempio di richiesta: curl -X POST -d "{\"test\": \"that\"}" http://localhost:8082/test

E qui è il codice, con i registri incorporati:

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

ha avuto modo di essere un modo migliore, giusto? Sono solo perplesso nel trovare quale potrebbe essere la migliore pratica.

(Go è anche conosciuto come Golang ai motori di ricerca, e di cui qui in modo che altri possano trovarla.)

+3

se si utilizza 'curl -X POST -H 'Content-Type: application/json' -d" {\ "test \": \ "that \"} "', quindi 'req.Form [" test " ] 'dovrebbe restituire' "che" ' – Vinicius

+0

@Vinicius ci sono prove di questo? – diraria

risposta

255

Utilizzare json.Decoder invece di 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) 
    } 
    defer req.Body.Close() 
    log.Println(t.Test) 
} 
+39

Potresti spiegare perché? –

+43

Per iniziare, sembra che questo possa gestire uno stream piuttosto che aver bisogno di caricarlo da solo in un buffer. (Sono un altro Joe BTW) – Joe

+4

Mi chiedo come sarebbe la corretta gestione degli errori in questo caso. Non penso che sia una buona idea farsi prendere dal panico per un jono non valido. – codepushr

48

è necessario leggere da req.Body. Il metodo ParseForm sta leggendo da req.Body e quindi analizzandolo nel formato codificato HTTP standard. Quello che vuoi è leggere il corpo e analizzarlo in formato JSON.

Ecco il codice aggiornato.

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

Probabilmente non lo capisco, ma non mi restituirebbe quello che ho già in '' req * http.Request'''? – TomJ

+0

In realtà, ho aggiornato la risposta. La mia prima risposta è stata sbagliata. Ho provato questo. – Daniel

+0

Grazie! Vedo dove stavo andando male ora. Se chiamate '' 'req.ParseForm()' '', cosa che stavo facendo in precedenti tentativi di risolvere questo problema, prima di provare a leggere il '' 'req.Body''', sembra che il body out e '' 'La fine imprevista dell'input JSON''' viene lanciata quando si va a' '' Unmarshal''' (almeno nella 1.0.2) – TomJ

11

ho trovato il seguente esempio dalla documentazione veramente utile (fonte 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) 
    } 
} 

La chiave qui è che il PO stava cercando di decodificare

type test_struct struct { 
    Test string 
} 

... nel qual caso avremmo cadere il const jsonStream, e sostituire il Message struct con l'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) 
    } 
} 

Aggiornamento: Vorrei anche aggiungere che this post fornisce alcuni ottimi dati sulla risposta anche con JSON. L'autore spiega struct tags, di cui non ero a conoscenza.

Dal JSON normalmente non sembrano {"Test": "test", "SomeKey": "SomeVal"}, ma piuttosto {"test": "test", "somekey": "some value"}, è possibile ristrutturare la vostra struct in questo modo:

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

... e ora il tuo gestore analizzerà JSON utilizzando "un po 'in mano" in contrapposizione a "SomeKey" (che userete internamente).

+1

non viene compilato. Intendi req.Body, non r.Body –

+0

diverso da errore di battitura, quello che hai dato in test(), è una risposta superiore a quella accettata, dal momento che non crea inutilmente una copia stringa –

+0

Oops! Aggiornato l'errore di battitura - grazie per aver segnalato! – JohnnyCoder

23

Mi stavo facendo impazzire con questo problema esatto. My JSON Marshaller e Unmarshaller non stavano popolando la mia struttura Go. Quindi ho trovato la soluzione al https://eager.io/blog/go-and-json:

"Come in tutte le strutture di Go, è importante ricordare che solo i campi con la prima lettera maiuscola sono visibili a programmi esterni come il Marshaller JSON."

Successivamente, il mio Marshaller e Unmarshaller hanno funzionato perfettamente!

+0

Man stavo letteralmente gridando dopo questa soluzione del tuo lavoro. Grazie, oh mio dio. – AndreaM16

+1

Grazie mille! Questo merita il trono –

+0

Questo sembra essere un errore abbastanza comune :-) –