CORSプレフライトとOPTIONSの挙動
フロントでPOSTを叩いたら突然OPTIONSが飛んできた——それがCORSプレフライトです。いつ発生するのか、どう返せばよいのかを簡潔にまとめました。
いつ発生する?
Fetch Standardに従い、非シンプルリクエストが送られる前にブラウザがOPTIONSを送ります。
トリガー条件(代表例)
- メソッドがGET/HEAD/POST以外(PUT/PATCH/DELETEなど)。
- POSTでもContent-Typeがapplication/jsonなど「シンプルヘッダー」以外。
- カスタムヘッダー(X-…やAuthorizationなど)を送る場合。
ブラウザが送るヘッダー
プレフライトでは実際のリソース取得は行わず、サーバーに「この本番リクエストを送っていい?」と問い合わせます。
主なヘッダー
| ヘッダー | 意味 |
|---|---|
| Origin | リクエスト元のスキーム+ホスト+ポート。 |
| Access-Control-Request-Method | これから本番で送りたいメソッド。 |
| Access-Control-Request-Headers | これから本番で付けたいヘッダー一覧(小文字でカンマ区切り)。 |
サーバーの返し方
リソース本体は返しません。許可を明示するヘッダーのみを返します。
必須・主なヘッダー
| ヘッダー | 役割 |
|---|---|
| Access-Control-Allow-Origin | 許可するOrigin。ワイルドカードはCredentialsと併用不可。 |
| Access-Control-Allow-Methods | 許可するメソッド一覧(GET, POST, PUTなど)。 |
| Access-Control-Allow-Headers | 許可するリクエストヘッダー一覧。 |
| Access-Control-Max-Age | プレフライト結果をキャッシュする秒数。長くしすぎると設定変更の反映が遅れる。 |
| Access-Control-Allow-Credentials | CookieやAuthorizationを許可する場合にtrueを返す。*とは併用不可。 |
レスポンスコード
- 204 No Contentで返すのがシンプル。200でも可だがボディは不要。
- 許可しない場合は403などを返し、Allow系ヘッダーは付けない。
よくある落とし穴
ヘッダーの不一致や大小文字が原因で失敗しがちです。
チェックリスト
- Access-Control-Allow-Headersはクライアントが送るヘッダー名と厳密一致させる(小文字化も含め)。
- Credentialsを許可するならAllow-Originを具体的なOriginに限定し、*を避ける。
- OPTIONSリクエストも認証やルーティングで拒否されないようにミドルウェア順序を確認。
- Access-Control-Max-Ageが長すぎると設定変更が反映されない。デバッグ時は短めに。
まとめ
プレフライトは「許可ヘッダーだけ返す」軽量応答。Allowヘッダー類をOriginに合わせて正しく返せば、実リクエストはスムーズに通ります。