ゆるテックノート

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に合わせて正しく返せば、実リクエストはスムーズに通ります。