🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
Go

Go(golang)は、Googleで開発されたオープンソースのプログラミング言語です。

JSON

JSON(JavaScript Object Notation)は軽量なデータ記述言語の1つである。構文はJavaScriptをベースとしていますが、JavaScriptに限定されたものではなく、様々なソフトウェアやプログラミング言語間におけるデータの受け渡しが行えるように設計されています。

Q&A

解決済

2回答

1588閲覧

「Go言語」フォームから送信されたJSONをサーバー側で受け取れない..............

uk_63

総合スコア29

Go

Go(golang)は、Googleで開発されたオープンソースのプログラミング言語です。

JSON

JSON(JavaScript Object Notation)は軽量なデータ記述言語の1つである。構文はJavaScriptをベースとしていますが、JavaScriptに限定されたものではなく、様々なソフトウェアやプログラミング言語間におけるデータの受け渡しが行えるように設計されています。

0グッド

0クリップ

投稿2019/02/13 05:40

編集2019/02/14 02:39

はじめに

質問を読んでくださりありがとうございます。

環境
mac
go 1.11

Go言語の勉強のためにWebアプリケーションを作っています。
そこでブラウザのformからから送信されたデータをJSONに変換して、構造体にマッピングし、SQLに保存したいと考えています。しかし、ブラウザから送信されたデータをJSONに変換できず、詰まっています。

なので、まずはブラウザから送信されたデータをJSONに変換して構造体へマッピング、コンソール上に表示までができるようになりたいです。

試したこと

こちらの記事「jQueryでJSONをPOSTしてJSONのレスポンスを受け取る」を参考にしてJSONをフォームからの送信を試みましたが、失敗しました。

コード(追記 2/14)

クライアント側で、JSONデータをアラートで出すようにしたところ、クライアントから送信されたデータはJSONに変換されています。しかし、サーバー(GO)でそのJSONを受け取ってコンソールに出力しようとしたら、エラーが出ています。

レスポンスのボディを出力するようにfmt.Print(r.Body)とした結果が下記です。

&{0xc0000aa520 <nil> <nil> false true {0 0} false false false 0x129bc20}

またそのデータをデコードした結果、出力されたエラーが下記です。

invalid character 'i' in literal true (expecting 'r')

デコードしているGoのコード

go

1func roomCreate(w http.ResponseWriter, r *http.Request) { 2 var room model.Room 3 if r.Body == nil { 4 fmt.Printf("レスポンスボディは空です。\n") 5 } 6 err := json.NewDecoder(r.Body).Decode(&room) 7 if err != nil { 8 fmt.Printf("エラー内容\n「%v」\n", err) 9 } 10 fmt.Printf("データ\n%v\n", room) 11 http.Redirect(w, r, "/room", 302) 12}

下記が全体のコードになります。

html

1 <form id="roomForm" method="POST" action="/room/new"> 2 <div class="form-group"> 3 <label>掲示板の名前</label> 4 <input type="text" name="title" id="roomTitle" class="form-control"> 5 </div> 6 <div class="form-group"> 7 <label>掲示板の説明</label> 8 <textarea name="content" rows="3" id="roomContent" class="form-control"></textarea> 9 </div> 10 <button type="submit">作成する</button> 11 </form>

js

1$(function () { 2 $("#roomForm").on('submit', function () { 3 $("#roomForm").attr("disable", true); 4 $.ajax({ 5 method: 'POST', 6 url: '/routes_room.go', 7 contentType: 'application/json', 8 dataType: 'JSON', 9 scriptCharset: 'utf-8', 10 cache: 'false', 11 timeout: 10000, 12 data: { 13 "title": $("#roomTitle").val(), 14 "content": $("#roomContent").val() 15 } 16 }) 17 .done((data) => { 18 alert(data) 19 }) 20 .fail((data) => { 21 alert(data) 22 }) 23 .always(() => { 24 $("#roomForm").attr("disable", false); 25 }); 26 }); 27}); 28 29

go

1type Room struct { 2 ID int `json:"id"` 3 Title string `json:"subject"` 4 Content string `json:"content"` 5 CreatedAt time.Time `json:"created_at"` 6} 7 8func roomCreate(w http.ResponseWriter, r *http.Request) { 9 var room model.Room 10 if r.Body == nil { 11 fmt.Printf("レスポンスボディは空です。\n") 12 } 13 err := json.NewDecoder(r.Body).Decode(&room) 14 if err != nil { 15 fmt.Printf("エラー内容\n「%v」\n", err) 16 } 17 fmt.Printf("データ\n%v\n", room) 18 http.Redirect(w, r, "/room", 302) 19} 20 21func main() { 22 mux := http.NewServeMux() 23 24 files := http.FileServer(http.Dir("assets")) 25 mux.Handle("/static/", http.StripPrefix("/static/", files)) 26 27 mux.HandleFunc("/", homeIndex) 28 mux.HandleFunc("/room/", roomIndex) 29 mux.HandleFunc("/room/new", roomCreate) 30 31 server := http.Server{ 32 Addr: "127.0.0.1:8080", 33 Handler: mux, 34 } 35 log.Fatal(server.ListenAndServe()) 36} 37

コード(追記2)

フォームから送信すると、以前まで成功していたのが$.ajaxの結果がfailになっています。HTML, JSのコードがおかしくないかみていただけますか?

html

1// actionの指定を消しました。 enctypeを追加しました。 2 3<form id="roomForm" enctype="application/json" method="post"> 4 <div class="form-group"> 5 <label>掲示板の名前</label> 6 <input type="text" name="title" value="Go言語コミュニティ" id="roomTitle" class="form-control"> 7 </div> 8 <div class="form-group"> 9 <label>掲示板の説明</label> 10 <textarea name="content" rows="3" id="roomContent" class="form-control"></textarea> 11 </div> 12 <button type="submit">作成する</button> 13 </form>

js

1// url の指定を変えました。 2// JSON.stringify(data)を付け加えました。 3// この処理の結果はなぜかfailになります。 4$(function () { 5 $("#roomForm").on('submit', function () { 6 $("#roomForm").attr("disable", true); 7 let data = { 8 title: $("#roomTitle").val(), 9 content: $("#roomContent").val() 10 }; 11 $.ajax({ 12 method: 'post', 13 url: '/room/new', 14 data:JSON.stringify(data), 15 dataType: 'json', 16 contentType: "application/json", 17 timeout: 10000, 18 }) 19 .done((data) => { 20 alert(data); 21 }) 22 .fail((data) => { 23 alert("ERROR"); 24 alert(data); 25 }) 26 .always(() => { 27 $("#roomForm").attr("disable", false); 28 }); 29 return false 30 }); 31}); 32 33

すべてのバリデーションを通過し成功しました。

go

1func roomCreate(w http.ResponseWriter, r *http.Request) { 2 fmt.Print("roomCreate is starting!!\n") 3 // validation 4 if r.Method != "POST" { 5 fmt.Printf("メソッド : \n%v\n", r.Method) 6 w.WriteHeader(http.StatusBadRequest) 7 return 8 } 9 fmt.Print("バリデーション1 通過\n") 10 11 if r.Header.Get("Content-Type") != "application/json" { 12 fmt.Printf("レスポンスヘッダー : \n%v\n", r.Header.Get("Content-Type")) 13 w.WriteHeader(http.StatusBadRequest) 14 return 15 } 16 fmt.Print("バリデーション2 通過\n") 17 18 //To allocate slice for request body 19 length, err := strconv.Atoi(r.Header.Get("Content-Length")) 20 if err != nil { 21 fmt.Printf("コンテンツレングス : \n%v\n", r.Header.Get("Content-Length")) 22 w.WriteHeader(http.StatusInternalServerError) 23 return 24 } 25 fmt.Print("バリデーション3 通過\n") 26 27 body := make([]byte, length) 28 length, err = r.Body.Read(body) 29 if err != nil && err != io.EOF { 30 w.WriteHeader(http.StatusInternalServerError) 31 return 32 } 33 fmt.Print("バリデーション4 通過\n") 34 35 var room model.Room 36 err = json.Unmarshal(body[:length], &room) 37 if err != nil { 38 w.WriteHeader(http.StatusInternalServerError) 39 return 40 } 41 fmt.Print("バリデーション5 通過\n") 42 fmt.Printf("%v\n", room) 43 w.WriteHeader(http.StatusOK) 44 http.Redirect(w, r, "/room", 302) 45} 46

質問

なぜJSONをサーバー側で受け取れていないんでしょうか?

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

ベストアンサー

2/14追記を見ずに書いた回答

https://github.com/roman01la/JSONFormData こちらを利用するなどして
Javascript側でJSONにしてPOSTさせるのが一般的ですね。

(ちなみにformの属性enctype="application/json" というのはW3Cで検討中の仕様で
まだほとんどのブラウザは対応できていません。サポートされたらscript部分は不要になる予定。)

html

1<form enctype="application/json" method="post"> 2 <input name="name" value="Bender" /> 3 <select name="hind"> 4 <option selected>Bitable</option> 5 <option>Kickable</option> 6 </select> 7 <input type="checkbox" name="shiny" checked /> 8 <input type="submit" value="Test" /> 9</form> 10<script src="./json-formdata.js"></script> 11<script> 12 Array.from( 13 document.querySelectorAll("form[enctype='application/json']"), 14 e => new JSONFormData(e, () => {}) 15 ); 16</script>

2/14追記への回答
いくつか指摘を

  • post先のurlがGoのソースファイルになっていますよ!(ハンドルされるURLでなければなりません)
  • r.Bodyがnilになることはないのでnilチェックは不要
  • fmt.Print(r.Body)ではポストされた内容は見れません。io.Copy(os.Stdout, r.Body)等を使いましょう。
  • 参考サイトの通りにdataを組めていません「JSON.stringify」が無いです。
  • また、submitイベントの伝搬を止めるためにsubmitコールバック記述の最後に「return false」が必要です。(これがない場合、ajaxによるポストの後に従来のformのsubmitが実行されます。)

投稿2019/02/14 01:51

編集2019/02/14 02:24
nobonobo

総合スコア3367

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

uk_63

2019/02/14 02:37

JSのエラーが気になりますが、GOでJSONを受け取ることに成功しました。 追記2にてコードを載せていますので、ご指摘いただけたら幸いです。
nobonobo

2019/02/14 03:50 編集

1. ajaxのdataType指定はレスポンスのフォーマット指定です。 2. ajaxリクエストの結果ステータスがリダイレクトの場合それも再リクエスト(通信を)を繰り返します。 3. 最終的にajaxリクエストが受け取るレスポンスコンテンツは「/room」をGETした結果になる。 4. 1.による指定でレスポンスコンテンツがJSONであることを期待しているのにHTMLが返されるのでJSONのデコードに失敗します。 というように色んなことをいっぺんにやってくれるjQueryライブラリは便利ですがトラブルの原因をわかりにくくします。僕の示したサンプルではjQueryを使いません。jQueryを採用するのかしないのかどちらにするのかは決めてください。jQueryを使うのならjQueryのリファレンスをしっかり読みましょう。
uk_63

2019/02/14 13:02

丁寧にありがとう御座います。参考にさせていただきます。
guest

0

GO言語を使っている皆様はブラウザのフォームから送信されたデータをどのようにJSONへ変換されていますか?

サーバー(go)側でクライアントからPOSTされてきたフォームデータをJSONに変換すると言う事でしょうか?
質問の回答とは少々異なりますが、もしそうであればクライアントで側でJSONにしてからPOSTすると良いかと思います。

投稿2019/02/13 17:29

編集2019/02/13 17:31
teikoku-penguin

総合スコア314

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

uk_63

2019/02/13 23:43

回答ありがとうございます。 クライアント側でJSONに変換する方法としては、jQuery でform の submit等にイベントを登録する。みたいな感じでしょうか?
uk_63

2019/02/14 01:10

クライアント側からJSONに変換することに成功しましたが、サーバー側(Go)で上手く受け取れていません。質問に追記しましたので、回答いただけませんか?
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.36%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問