質問をすることでしか得られない、回答やアドバイスがある。

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

新規登録して質問してみよう
ただいま回答率
85.48%
Go

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

POST

POSTはHTTPプロトコルのリクエストメソッドです。ファイルをアップロードしたときや入力フォームが送信されたときなど、クライアントがデータをサーバに送る際に利用されます。

React.js

Reactは、アプリケーションのインターフェースを構築するためのオープンソースJavaScriptライブラリです。

Q&A

解決済

1回答

1691閲覧

Goで作成したAPIにReactでPOSTしたい

takeya60

総合スコア2

Go

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

POST

POSTはHTTPプロトコルのリクエストメソッドです。ファイルをアップロードしたときや入力フォームが送信されたときなど、クライアントがデータをサーバに送る際に利用されます。

React.js

Reactは、アプリケーションのインターフェースを構築するためのオープンソースJavaScriptライブラリです。

0グッド

0クリップ

投稿2022/06/22 14:52

編集2022/06/22 15:13

やりたいこと

Goの勉強でTodoアプリを作成しています。
ReactでPOSTリクエストしたデータをGoで読み込みたいです。

実装

Go サーバーサイド

Go

1コード 2package todos 3 4import ( 5 "database/sql" 6 "encoding/json" 7 "fmt" 8 "io/ioutil" 9 "log" 10 "net/http" 11 "os" 12 "strings" 13 "time" 14 "todo-app/auth" 15 16 "github.com/joho/godotenv" 17) 18 19type Todo struct { 20 // UserID int `json:"userid"` 21 Todo string `json:"todo"` 22 CreatedAt time.Time `json:"createdat"` 23 UpdatedAt time.Time `json:"updatedat"` 24} 25 26type TodoBody struct { 27 Todo string `json:"todo"` 28} 29 30func CreateTodo(w http.ResponseWriter, r *http.Request) { 31 w.Header().Set("Content-Type", "*") 32 w.Header().Set("Access-Control-Allow-Origin", "http://localhost:3000") 33 w.Header().Set("Access-Control-Allow-Credentials", "true") 34 w.Header().Set("Access-Control-Allow-Headers", "*") 35 36 e := godotenv.Load() 37 if e != nil { 38 log.Fatal(e) 39 } 40 dbConnectionInfo := fmt.Sprintf("%s:%s@tcp(127.0.0.1:3306)/go_todo", os.Getenv("DB_USER"), os.Getenv("DB_PASSWORD")) 41 db, err := sql.Open("mysql", dbConnectionInfo) 42 if err != nil { 43 log.Fatal(err) 44 } 45 defer db.Close() 46 47 body, err := ioutil.ReadAll(r.Body) 48 if err != nil { 49 log.Fatal(err) 50 51 } 52 53 log.Printf("request body=%s\n", body) 54 55 var data TodoBody 56 57 if err := json.Unmarshal(body, &data); err != nil { 58 log.Println(err) 59 } 60 61 // userId := 12 62 todo := data.Todo 63 64 todoData := Todo{todo, time.Now(), time.Now()} 65 66 tokenString := r.Header.Get("Authorization") 67 tokenString = strings.TrimPrefix(tokenString, "Bearer ") 68 69 log.Printf("request token=%s\n", tokenString) 70 71 _, err2 := auth.TokenVerify(tokenString) 72 if err2 != nil { 73 log.Fatal(err) 74 } else { 75 76 stmt, err := db.Prepare("INSERT INTO todos (Todo,CreatedAt,UpdatedAt) VALUES(?,?,?)") 77 if err != nil { 78 log.Fatal(err) 79 } 80 81 _, err = stmt.Exec(todoData.Todo, todoData.CreatedAt, todoData.UpdatedAt) 82 if err != nil { 83 log.Fatal(err) 84 } 85 86 json.NewEncoder(w).Encode(todoData) 87 } 88} 89

React フロントエンド

React

1import { useState } from "react"; 2import { useCreateTodo } from "../../hooks/useCreateTodo"; 3import { BaseButton } from "../atoms/baseButton"; 4import { TextArea } from "../atoms/textArea"; 5 6export const AddTodo = () => { 7 const [text, setText] = useState(""); 8 const CreateTodo = useCreateTodo(); 9 const token = "Bearer " + sessionStorage.getItem("token"); 10 11 const onClickCreate = () => { 12 CreateTodo(token, text); 13 }; 14 15 return ( 16 <div> 17 <TextArea 18 onChange={(e: any) => setText(e.target.value)} 19 defaultValue="" 20 /> 21 22 <BaseButton text="タスクを追加" onClick={onClickCreate} /> 23 </div> 24 ); 25}; 26

ここでPOSTしています↓

React

1import axios from "axios"; 2 3export const useCreateTodo = () => { 4 const URL = "http://127.0.0.1:8080/createtodo"; 5 6 const CreateTodo = async (token: string, todo: any) => { 7 const data = { todo: todo }; 8 console.log(data); 9 10 await axios 11 .post(URL, JSON.stringify(data), { headers: { Authorization: token } }) 12 .then((res) => console.log(res)) 13 .catch((err) => console.log(err)); 14 }; 15 16 return CreateTodo; 17}; 18

POSTする際にheaderをつけなければGoのioutil.ReadAll(r.Body)に正しい値が来ていますが、headerを加えると値がとれなくなります。
Advanced REST clientでGoのAPIをたたいた際にはheaderの情報があっても正しく処理されているので、POSTの仕方に問題があるかと考えていますが、なかなか解決することができません。ブラウザのコンソールにはこちらが表示されています。 POST http://127.0.0.1:8080/createtodo net::ERR_CONNECTION_RESET
お力を貸していただけたら幸いです。よろしくお願いします。

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

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

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

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

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

hoshi-takanori

2022/06/22 14:59

ブラウザのコンソールに何か出てますか?
hoshi-takanori

2022/06/22 22:23

サーバーが log.Fatal で落ちてるとか?
guest

回答1

0

ベストアンサー

フロントエンドとGoバックエンドが「ホストまたはポート」が異なるところから提供されている場合、
クロスオリジンリソース共有(CORS)対応が求められると思いますが、
Go側にその対応を入れているのが

go

1 w.Header().Set("Access-Control-Allow-Origin", "http://localhost:3000")

これだけのように見えます。

ブラウザはセキュアなクロスオリジンなAPIアクセスにおいて、サーバーやクライアントの許可ヘッダーを確認しようとします。

クライアントに特に許可ヘッダーがない場合、
プリフライトチェックという「OPTIONS」メソッドによるリクエスト・レスポンスのやり取りを先行して行おうとします。ここでエラーがあると、サーバーだけ許可ヘッダーがあっても切断される場合があるかもしれません。

解決案1:
クライアントに全許可を入れる方法

javascript

1axios.defaults.headers.post['Access-Control-Allow-Origin'] = '*';

解決案2:
サーバー側にOPTIONS応答を返す実装を追加する。

実装例:

w.Header().Set("Access-Control-Allow-Origin", "http://localhost:3000") switch r.Method { case "OPTIONS": w.Header().Set("Access-Control-Allow-Headers", "access-control-allow-methods,access-control-allow-origin") w.Header().Set("Access-Control-Allow-Methods", "GET, POST, OPTIONS") return } // 通常の応答実装

投稿2022/06/22 22:45

編集2022/06/23 04:20
nobonobo

総合スコア3367

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

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

nobonobo

2022/06/22 22:55

もちろん解決案1を公の場に使うのはやめましょう。セキュリティ的に狙われやすくなる可能性を増やしてしまいます。
takeya60

2022/06/23 01:18

解答ありがとうございます。解決策1を試してみましたが、同じ現象が発生してしまいます。 解決策2について調べてみようと思います。
nobonobo

2022/06/23 04:27

解決案1はもう使えなくなってますね。(ブラウザがよりセキュアに改良された?) 案2の実装例を追記しました。
takeya60

2022/06/23 05:16

実装例をコードに追加したら想定通りに動きました!追記していただきとても助かりました。 ありがとうございます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問