今更ながらORIGINの違う(≒クロスドメイン)のAPIをブラウザからのJavaScriptで叩くときにCORSとかいろいろとありがとうございました。
JavaScriptがドメインを越えるにはCORS設定をしなければならない。ドメインというか、正確にはORIGINだけど。
ORIGINってこの3つから成り立ってる。
| 項目 | 例 |
|---|---|
| スキーム | http / https |
| ホスト名 | example.com / localhost |
| ポート | 80, 443, 3000, etc. |
以下、ブラウザが表示しているWEBページを http://localhost:8080 (送信元ORIGIN)として、そのWEBページからXHRで叩きたいAPIを http://localhost:8000(API ORIGIN)とする。
API側は、CORSヘッダを適切にブラウザに返さなければならない。
送ってきたリクエストに対してCORS(Cross-Origin Resource Sharing)が成立するためには以下のヘッダを適切に送らなければならない。適切にというのは、イケナイ送信元ORIGINだったらこれらを送らないということです。サンプルはPHPのSlim Frameworkだが、まあだいたいわかるだろう。
<?php // $originは(送信元ORIGIN)であること。 $response = $response->withHeader('Access-Control-Allow-Origin', $origin) ->withHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization') ->withHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS'); return $response;
CORSエラーの場合にJavaScriptではどうするか。
axiosを使っている場合だが、CORS エラーが発生した場合、サーバーからのレスポンスがJavaScriptまで届かないようにブラウザがブロックしてしまう。なのでこんな感じでCORSエラーを処理する。
try { await axios.post(url, data); } catch (e) { if (axios.isAxiosError(e)) { if (e.response === undefined && e.request !== undefined){ alert('ネットワークエラー'); } setErrors(e.response?.data.errors); } }
COOKIEを使いたい場合
更にCOOOKIEについてもCORSが成立するために、はヘッダーが必要である。これはクライアントとサーバーの両方で必要になる。
クライアント側(JavaScript)
// fetch fetch('https://api.example.com/endpoint', { method: 'POST', credentials: 'include', // ← これが必須 }); // axios axios.post(url.confirm, data, { withCredentials: true });
サーバ側(PHPのSlim Framework)
<?php $response = $response->withHeader('Access-Control-Allow-Origin', $origin) ->withHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization') ->withHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS') ->withHeader('Access-Control-Allow-Credentials', 'true'); // trueではなく文字列の"true"
すげぇ面倒です。
サーバ側(追加)
POSTの前にはPreflightがOPTIONメソッドで飛ぶので、全てのPOSTルーティングに対してOPTIONルートも同様のCORS対応ヘッダを送るようにしないといけないよ。