はじめに
CORS(Cross-Origin Resource Sharing)やプリフライトリクエストについてハマったのでその辺をまとめておきます。
CORSとは
オリジンとは
オリジンとは、以下の3つの組み合わせです。
| 要素 | 例 |
|---|---|
| スキーム(プロトコル) | https:// |
| ホスト(ドメイン) | api.example.com |
| ポート番号 | :443 |
3つがすべて一致する場合のみ「同一オリジン」です。1つでも違えば「異なるオリジン」になります。
| URL |
https://app.example.com との関係 |
|---|---|
https://app.example.com/about |
✅ 同一オリジン(パスが違うだけ) |
https://api.example.com |
❌ 異なるオリジン(ホストが違う) |
http://app.example.com |
❌ 異なるオリジン(スキームが違う) |
https://app.example.com:8080 |
❌ 異なるオリジン(ポートが違う) |
同一オリジンポリシー(Same-Origin Policy)とは
次にCORSを理解するには 同一オリジンポリシー を知る必要があります。
ブラウザには、セキュリティのために 異なるオリジンからのレスポンスを JavaScript に読み取らせないというルールがあります。これが同一オリジンポリシーです。
https://app.example.com から https://api.example.com へのリクエストは異なるオリジンなので、リクエスト自体はサーバーに届いても、ブラウザがレスポンスを JavaScript に渡しません。

CORSとは
CORS(Cross-Origin Resource Sharing) は、異なるオリジン間でのリソース共有を安全に行うための仕組みです。
サーバー側が「このオリジンからのアクセスは許可するよ!」とブラウザに伝えることで、クロスオリジンのリクエストを解禁できます。
CORSヘッダーについても後述しますが、ここではCORSを許可するために付与される情報だと考えておけば大丈夫です。
主要なCORSヘッダー
サーバーが返すCORSヘッダーの種類は以下のとおりです。
| ヘッダー名 | 説明 | 例 |
|---|---|---|
Access-Control-Allow-Origin |
許可するオリジン |
https://app.example.com または *
|
Access-Control-Allow-Methods |
許可するHTTPメソッド | GET, POST, PUT, DELETE |
Access-Control-Allow-Headers |
許可するリクエストヘッダー | Content-Type, Authorization |
Access-Control-Allow-Credentials |
Cookieなどの認証情報を許可するか | true |
Access-Control-Max-Age |
プリフライト結果のキャッシュ時間(秒) | 3600 |
プリフライトリクエスト(Preflight Request)とは
次にプリフライトリクエストについてです。
プリフライトリクエストとは、本番のリクエストを送る前に「このリクエストを送っても大丈夫ですか?」とサーバーに事前確認する仕組みです。HTTPのOPTIONSメソッドを使って確認します。
なぜこの仕組みが必要かというと、前述のとおりCORSはレスポンスをブラウザがブロックする仕組みです。しかし、リクエスト自体はサーバーに届くため、DBへの書き込みなど副作用のある操作が実行されてしまってから「見せられない」となっては遅いケースがあります。プリフライトはそれを事前に防ぐためのガードです。
プリフライトが必要な条件
すべてのクロスオリジンリクエストがプリフライトを送るわけではありません。以下の シンプルリクエスト の条件をすべて満たす場合は、プリフライトなしで直接リクエストが送られます。
シンプルリクエストの条件:
- メソッドが
GET、POST、HEADのいずれか - カスタムヘッダーを含まない(
Content-Typeはapplication/x-www-form-urlencoded、multipart/form-data、text/plainのみ)
条件を満たさない場合(例:Content-Type: application/json や Authorization ヘッダーを使う場合)は、プリフライトリクエストが必要 になります。
プリフライトリクエストの流れ
プリフライトリクエストとは、「本番のリクエストを送っても大丈夫ですか?」とサーバーに事前確認する仕組みです。HTTP の OPTIONS メソッド を使います。
ポイント:
- ① プリフライトで「これからこんなリクエストを送りたい」と事前確認
- ② サーバーが許可なら200で返す
- ③ 許可されたら本番リクエストを送る
-
Access-Control-Max-Ageを設定すると、一定時間プリフライトの結果をキャッシュして2回目以降はスキップできる
プリフライトが失敗するケース
プリフライトが失敗すると、本番リクエストはブロックされます。よくある原因は以下のとおりです。
- サーバー側でCORSヘッダーが設定されていない
-
Access-Control-Allow-Originに該当オリジンが含まれていない -
Access-Control-Allow-Methodsに使いたいメソッドが含まれていない -
Access-Control-Allow-Headersにカスタムヘッダーが含まれていない
ヘッダーの設定はAPI Gatewayで行う場合、コンソール上から行えます。
さいごに
CORSとプリフライトリクエストについてまとめます:
| 項目 | まとめ |
|---|---|
| CORS | 異なるオリジン間でのリソース共有を許可する仕組み |
| プリフライト | 本番リクエスト前にサーバーへ事前確認するOPTIONSリクエスト |
| 必要な条件 | カスタムヘッダーや application/json を使う場合など |
| AWSでの対応 | API Gateway・Lambda・S3・CloudFront それぞれで設定が必要 |
「CORSエラーが出たらとりあえず Access-Control-Allow-Origin: * にする」はセキュリティ的にNGです。本番環境では必ず特定のオリジンを指定しましょう。
次回は実際の実装例や設定について書いていこうと思います。
この記事が参考になれば幸いです。
参考


