CORSエラー(Cross-Origin Resource Sharing Error)とは?「Access-Control-Allow-Origin」「プリ フライト リクエスト」

CORSエラーとは

CORSは「異なるオリジン(ドメイン、プロトコル、ポート)間でのリソース共有」を制御するセキュリティの仕組みです。

そのため異なるオリジン間でリソースをリクエストしようとする際にブラウザが制限をかけることにより、CORSエラーが発生します。

ウェブサイト localhost:3000 fetch(‘/api/data’) APIサーバー localhost:8000 Access-Control-Allow-* ブラウザ CORSチェック ✓ オリジンの確認 ✓ メソッドの許可 ✓ ヘッダーの確認 CORSエラーが発生する場合: 1. オリジンの不一致(例:localhost:3000からのリクエストに対し、サーバーが異なるオリジンを許可) 2. 許可されていないHTTPメソッド(GET/POST/PUT等)の使用

「Access-Control-Allow-Origin」の設定

異なるオリジン間のリクエストで制限をうけずにアクセスするためには、レスポンスヘッダーに「Access-Control-Allow-Origin」を指定することで可能になります。

https://zenn.dev/syo_yamamoto/articles/445ce152f05b02

プリフライトリクエストとは

異なるオリジン(ドメイン)へリクエストを送る前の「事前確認」

  • 本来のリクエストを送る前に、そのリクエストが安全かどうかを確認します
  • HTTPのOPTIONSメソッドを使用して送信されます

プリフライトリクエストはブラウザが自動的に行います。開発者が明示的にコードを書く必要はありません。

プリフライトが必要になるケース

  • 特殊なヘッダーを使用する場合
  • application/jsonなどの特殊なContent-Typeを使用する場合
  • GET/POST/HEAD以外のメソッド(PUT、DELETEなど)を使用する場合

プリフライトリクエストの流れ

ブラウザがOPTIONSリクエストを送信 サーバーがCORS設定を返答 許可された場合のみ、本来のリクエストを送信

CORSリクエストパターン パターン1: Simple Request (プリフライトなし) フロントエンド API サーバー GETリクエスト/通常フォーム送信 パターン2: プリフライト成功パターン フロントエンド API サーバー 1. OPTIONSリクエスト 2. CORS OK 3. 本来のリクエスト パターン3: プリフライト失敗パターン フロントエンド API サーバー 1. OPTIONSリクエスト 2. CORS エラー 本来のリクエストは送信されない

開発者ツールでの確認方法

  1. ブラウザの開発者ツールを開く
  2. Networkタブで確認
    • OPTIONSメソッドのリクエスト → これがプリフライトリクエスト
    • その直後の本来のリクエスト

リクエストヘッダー:

  • Origin: [送信元のドメイン]
  • Access-Control-Request-Method: [使用予定のメソッド]
  • Access-Control-Request-Headers: [使用予定のヘッダー]

レスポンスヘッダー:

  • Access-Control-Allow-Origin: [許可されているドメイン]
  • Access-Control-Allow-Methods: [許可されているメソッド]
  • Access-Control-Allow-Headers: [許可されているヘッダー]
Elements Network Console Name Method Status /api/data OPTIONS 204 /api/data POST 200 プリフライトリクエストの確認方法: 1. ブラウザの開発者ツールを開く (F12 または右クリック → 検証) 2. Networkタブを選択 3. OPTIONSメソッドのリクエストを探す 4. リクエストをクリックすると詳細が表示される: – Request Headers: Origin, Access-Control-Request-Method – Response Headers: Access-Control-Allow-Origin, Methods, Headers

ステータスコード(参考)

HTTPのレスポンスヘッダの先頭に必ず入ってます

ステータスコード名前説明
200OKリクエスト成功
202Acceptedリクエスト成功したが、処理はまだ
301Moved Permanentlyリソースは恒久的に移動
302Foundリクエストしたリソースは一時的に移動
307Temporary Redirectリクエストしたリソースは一時的に移動
400Bad Requestリクエストが正しくない
403Forbiddenアクセスが禁止されている
404Not Found指定したリソースが見つからない
405Method Not Allowed指定したメソッドを使えません
406Not AcceptableAccept関連のヘッダに問題
413Request Entity Too Largeリクエストボディが大きすぎる
415Unsupported Media Typeサポートしていないメディアタイプ
429Too Many Requestsリクエスト回数が多すぎる
500Internal Server Errorサーバー側でエラーが発生
503Service Unavailableサーバーが一時的に停止

(注意)プリフライトリクエストを扱うPHPスクリプトの設計

クロスオリジン(別ドメインからのfetchなど)を想定したPHPスクリプトでは、必ずOPTIONSリクエストへの対応が必要です。

<?php
// CORSヘッダー設定
header("Access-Control-Allow-Origin: https://example.com");
header("Access-Control-Allow-Methods: POST, OPTIONS");
header("Access-Control-Allow-Headers: Content-Type");

// OPTIONSリクエスト(プリフライト)への対応
if ($_SERVER['REQUEST_METHOD'] == 'OPTIONS') {
    exit();  // ← 必須!ここで終了
}

// 以下、本処理(POSTなど)
// データベース処理
// メール送信
// など
?>

上記のように記述しないとOPTIONメソッドリクエストと本リクエストで2重でPHPスクリプトの処理がコールされてしまいます。

クロスオリジンを扱うPHPでは、OPTIONSリクエストでexitして、メイン処理の重複実行を防ぐ必要があります