だから私は信じられないほどハックに思える次のものがあり、Goはこれよりもライブラリを設計した方が良いと考えてきましたが、JSONのPOSTリクエストを処理するGoの例を見つけることができませんデータ。それらはすべてフォーム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としても知られ、他の人が見つけられるようにここで言及されています。)
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)
}
req.Body
から読む必要があります。 ParseForm
メソッドは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))
}
私はこの正確な問題に夢中になっていました。私のJSON MarshallerとUnmarshallerは私のGo構造体を生成しませんでした。それから私は https://eager.io/blog/go-and-json で解決策を見つけました:
「Goのすべての構造体と同様に、頭文字が大文字のフィールドだけがJSON Marshallerのような外部プログラムに表示されることを忘れないでください。」
その後、私の元帥と元帥は完璧に働きました!
私はドキュメントから次の例がとても役に立つことを見つけました(source 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)
}
}
更新: この記事 は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"`
}
...そして今、あなたのハンドラは "SomeKey"(これは内部的に使用されます)ではなく "some-key"を使用してJSONを解析します。
json.Decoder
がjson.Unmarshal
よりも優先されるべきである理由は2つあります - 2013年の最も一般的な答えでは扱われていません。
go 1.10
は新しいメソッドを導入しました json.Decoder.DisallowUnknownFields() このメソッドは不要なJSON入力を検出する懸念に対処しますreq.Body
はすでにio.Reader
です。コンテンツ全体を読み取ってからjson.Unmarshal
を実行すると、ストリームが無効なJSONの10MBブロックであるとしたら、リソースが無駄になります。無効なJSONが検出された場合、json.Decoder
をストリームしながらリクエスト本文を解析すると、早期解析エラーが発生します。リアルタイムでI/Oストリームを処理することが好ましいgo-wayです。不適切なユーザー入力の検出に関するユーザーのコメントに対処する
必須項目やその他の衛生チェックを実施するには、次のことを試してください。
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)
典型的な出力:
$ 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