CORS は、ブラウザが別オリジンへのリクエストをどこまで許すかを決める仕組みです。正式には Cross-Origin Resource Sharing の略です。 サーバーがレスポンスヘッダーで「このオリジンには読ませてよい」と伝え、ブラウザがそれを見て判断します。
いちばん多い誤解
CORS はサーバーを守るセキュリティ機能ではありません。守っているのは、利用者のブラウザが勝手に別サイトのデータを読み取られることです。 証拠に、CORS で拒否される API でも curl やサーバー間通信からは普通に呼べます。「CORS を設定したからAPIは安全」は成り立たないので、認証・認可は別に必要です。
エラーが出ても API は壊れていない
CORS エラーの厄介なところは、サーバーは 200 を返しているのにブラウザが応答を読ませない点です。ログを見ると正常に処理されているのに、画面ではエラーになります。切り分けは次の順が早いです。
- DevTools の Network タブで、そのリクエストが実際にサーバーへ届いているか確認する
- 届いているなら、レスポンスに
Access-Control-Allow-Originが付いているか見る - リクエスト前に
OPTIONSが飛んでいないか見る(プリフライト)
プリフライトが飛ぶ条件
単純な GET / POST 以外、たとえば PUT や DELETE、Content-Type: application/json、独自ヘッダーを付けたリクエストでは、ブラウザが本番リクエストの前に OPTIONS で許可を確認します。
「GET は通るのに POST(JSON) だけ落ちる」の原因はほぼこれで、サーバー側が OPTIONS に応答していないことが多いです。ルーティングで OPTIONS を受けているか確認してください。
Cookie を使うときは * が使えない
認証情報(Cookie や Authorization ヘッダー)を伴う通信では、Access-Control-Allow-Origin: * は使えません。具体的なオリジンを1つ返し、さらに Access-Control-Allow-Credentials: true を付ける必要があります。
複数オリジンを許可したい場合は、リクエストの Origin を許可リストと突き合わせ、一致したものだけをそのまま返す実装にします。