事象
ReactアプリにてブラウザからfetchAPIを使って、別オリジンのサーバーにPOSTリクエストを送信しようとしたが、エラーが発生していました。
バックエンドはGo(コード記載なし)
fetch(url, {
method: 'POST',
mode: 'cors',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(data)
})
.then((res) => {
if (!res.ok) {
console.log(res);
throw new Error('Response is not ok at xxx api');
}
})
.catch(rejected => {
console.log(rejected);
});
Access to fetch at 'XXX' from origin 'http://localhost:3000' has been
blocked by CORS policy: Response to preflight request doesn't pass
access control check: No 'Access-Control-Allow-Origin' header is present
on the requested resource. If an opaque response serves your needs, set
the request's mode to 'no-cors' to fetch the resource with CORS disabled.
POST http://localhost:8080/xxx net::ERR_FAILED
TypeError: Failed to fetch
原因
エラー文から、Responseヘッダーに”Access-Control-Allow-Origin”が設定されていないためにpreflightリクエストが通らなかったとあります。Responseヘッダーに”Access-Control-Allow-Origin”を設定するか、リクエストのmodeを”no-cors”に設定しなければなりません。
しかし、バックエンド側のコードではResponseヘッダーに”Access-Control-Allow-Origin”を設定する処理を記述しているので、コードは動くはず、と思っていました。
解決策
バックエンド側でResponseヘッダーの設定の方法を間違えていたためでした。
fetchAPIを使用してGET以外のリクエストを投げると、そのリクエストが投げられる直前にPreFlightリクエストというのがクライアントからサーバーに投げられ、CORS対策がなされているかのチェックが行われます。(実際に投げたいリクエストを投げる際に合計2回のリクエストが発行されることになる)
バックエンド側ではルーティング処理後のAction内でResponseヘッダーの設定を行なっており、OPTIONメソッドのリクエストがきた場合に想定した関数内に処理が入っていきませんでした。
ルーティング処理前にCORS設定としてResponseヘッダーの各種設定を行う、さらにOPTIONメソッドのリクエストがきた場合に検知して200ステータスを返却する処理を追加したところ、動作するようになりました。
解決方法がわからなかった時は何がなんだかわかりませんでしたが、焦らず1つずつ理解して解消していくのが一番の近道ですね。