fetchリクエストを実行しました。ネットワークタブではそのリクエストが送信されたことが確認できますが、コンソールには赤いエラーメッセージが壁のように並んでいます。 オリジン「https://yourapp.com」から「https://api.example.com」へのfetchアクセスは、CORSポリシーによりブロックされました。
説明に入る前に、最も効率的な診断手順を紹介します。開発ツールを開き、ネットワークタブに移動し、失敗したリクエストを見つけ、そのリクエストの 応答ヘッダーを確認してください。もし Access-Control-Allow-Originが見られなければ、サーバーがCORSヘッダーを送信していないということです。これが解決策です。この記事の残りの部分では、正確にどのようなヘッダーを送るべきか、そしてなぜ送るべきかを説明します。
CORSが実際に何なのか
CORS(クロスオリジンリソース共有)はブラウザによって強制されます。サーバーがそのようなリクエストをブロックするわけではありません。ブラウザがユーザーの代わりにそのようなリクエストをブロックすることで、他のサイトのスクリプトが銀行データを静かに読み取るのを防ぎます。 evil.com ブラウザは「そのAPIからの応答が、このオリジンがそのデータを読み取る許可を受けているか」と確認します。許可されていない場合、応答はブロックされます。サーバーはそのリクエストが処理され、200を返したにもかかわらず、その結果がブラウザによって無視されてしまうことになります。
デバッグの際にこれが重要です。エラーは常にクライアント側に表示されます。サーバーはブラウザに「はい、このオリジンは許可されています」と伝える必要があります。それがCORS応答ヘッダーの役割です。
シンプルリクエストとプリフライトリクエスト
すべてのクロスオリジンリクエストが同じように振る舞うわけではありません。ブラウザは2つのタイプに分類します。
シンプルリクエスト
は、GETまたはPOSTリクエストで、テキストまたはフォームエンコードされたボディ、および少数の許可されたヘッダーを使用しています。ブラウザは直接それらを送信し、応答に を確認します。 Access-Control-Allow-Origin.
プリフライトリクエスト は、リクエストがその条件を満たさない場合に最初に発生します。たとえば、 PUT または DELETEを送信したり、カスタムヘッダー(例: Authorization または Content-Type: application/json)を含めたり、認証情報を送信する場合です。ブラウザは自動的に OPTIONS リクエストを同じURLに送信します。もしサーバーがその OPTIONS リクエストに対して適切なCORSヘッダーを返さない場合、実際のリクエストは送信されません。
ネットワークタブで OPTIONS リクエストが404または405を返している場合、それがリクエストが失敗する理由です。すべてのクロスオリジントラフィックを受け取るルートに対して、サーバーは OPTIONS を処理する必要があります。
重要なヘッダー
CORSヘッダーを正しく設定するには、各応答ヘッダーが実際に制御していることを理解することが必要です:
Access-Control-Allow-Origin— どのオリジンが応答を読み取ることができるか。特定のオリジン(https://yourapp.com)または*で、すべてのオリジンが許可されます。Access-Control-Allow-Methods— 使用できるHTTPメソッド(例:GET, POST, PUT, DELETE, OPTIONS).Access-Control-Allow-Headers— ブラウザが送信できるリクエストヘッダー(例:Authorization, Content-Type).Access-Control-Allow-Credentials— 認証情報やクッキーがリクエストと共に送られるかどうか。明示的にtrue必要です。Access-Control-Max-Age— プリフライト応答がキャッシュされる秒数を指定します。
ワイルドカードの罠
ワイルドカードを使用することはAPIを開放する最も簡単な方法ですが、認証情報が必要な場合にその効果が失われます。認証情報が要求される場合、ワイルドカードはブラウザによって拒否されます。正確なオリジンを指定する必要があります: Access-Control-Allow-Origin: * 複数の許可されたオリジンがある場合、リクエストの Access-Control-Allow-Credentials: true ヘッダーを読み取り、条件付きでその値を返す必要があります。値を結合しないでください。
# This will fail with credentials:
Access-Control-Allow-Origin: *
Access-Control-Allow-Credentials: true
# This works:
Access-Control-Allow-Origin: https://yourapp.com
Access-Control-Allow-Credentials: true
頻出するCORSエラーとその意味 Origin ブラウザのエラーメッセージは、欠落しているものを見つけるために非常に正確です。以下がその一例です:
エラーメッセージ
意味
| 解決策 | ‘Access-Control-Allow-Origin’ヘッダーが存在しません | サーバーがCORSヘッダーをまったく送信していません |
|---|---|---|
| 応答に | ‘Access-Control-Allow-Origin’ヘッダーの値…が提供されたオリジンと一致していません | 追加する Access-Control-Allow-Origin オリジンの不一致 — サーバーが誤ったまたは認証情報とともにワイルドカードを返した |
| リクエストのOriginヘッダーを条件付きで再送し、認証情報を使う場合はワイルドカードを削除してください | Method PUTはAccess-Control-Allow-Methodsで許可されていません | HTTPメソッドが許可されたメソッドヘッダーに含まれていません |
| 欠落したメソッドを | Request header ‘Authorization’はAccess-Control-Allow-Headersで許可されていません | カスタムヘッダーが許可リストに含まれていません Access-Control-Allow-Methods |
| ヘッダーを | Response to preflight request doesn’t pass access control check | OPTIONSリクエストが不正なステータスまたはヘッダーを返しました Access-Control-Allow-Headers |
| OPTIONSを明示的に処理し、200/204で正しいヘッダーを返してください | Credential is not supported if the CORS header ‘Access-Control-Allow-Origin’ is ‘*’ | ワイルドカードを使用して認証モードで |
| を置き換えて、明示的なオリジンに変更し、 | CORSを設定する方法(Express、FastAPI、Nginx) | Express(Node.js) * FastAPI(Python) Access-Control-Allow-Credentials: true |
Nginx
Nginxのパターンに注意してください:
const cors = require('cors');
app.use(cors({
origin: 'https://yourapp.com',
methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'],
allowedHeaders: ['Content-Type', 'Authorization'],
credentials: true,
maxAge: 86400
}));
// Handle preflight for all routes
app.options('*', cors());
は、
from fastapi.middleware.cors import CORSMiddleware
app.add_middleware(
CORSMiddleware,
allow_origins=["https://yourapp.com"],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
ブロックとメインブロックの両方に必要です。
location /api/ {
if ($request_method = 'OPTIONS') {
add_header 'Access-Control-Allow-Origin' 'https://yourapp.com';
add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, OPTIONS';
add_header 'Access-Control-Allow-Headers' 'Authorization, Content-Type';
add_header 'Access-Control-Allow-Credentials' 'true';
add_header 'Access-Control-Max-Age' 86400;
add_header 'Content-Length' 0;
return 204;
}
add_header 'Access-Control-Allow-Origin' 'https://yourapp.com';
add_header 'Access-Control-Allow-Credentials' 'true';
proxy_pass http://backend;
}
Note the Nginx pattern: you need add_header ブロック内のヘッダーは、外部ブロックに引き継がれません。 OPTIONS デバッグチェックリスト if CORSエラーが発生した場合、以下の順に進めてください:
エラーメッセージを確認
— それは正確にどのヘッダーまたは値が間違っているかを示しています。
- ネットワークタブを確認 — 実際の応答ヘッダーを見て、自分が設定したものと一致しているか確認してください。
- OPTIONSリクエストの確認 — それが失敗したり存在しない場合、サーバーがプリフライトを処理していないということです。
- オリジンが正確に一致しているか確認 — 末尾のスラッシュ、HTTPとHTTPS、ポート番号などすべて重要です。
- 認証情報を使う場合はワイルドカードを削除 — これらは互いに排他的です。
- プロキシがヘッダーを削除しているか確認 — NginxやCDNは時々CORSヘッダーを削除または上書きします。
- 簡単に見落としがちなこと:APIが逆プロキシまたはCDNの背後にある場合、その層が独自の ヘッダーを追加することがあり、それがアプリケーションサーバーが返すCORSヘッダーと衝突します。その結果、2つのヘッダーが1つの応答に含まれると、ブラウザはそのすべてを拒否します。ネットワークレベルでの原始応答ヘッダーを確認してください。アプリケーションコードが生成したものだけではなく、そのすべてを確認してください。
もう一つの特殊ケース:一部のフレームワークは、登録されたハンドラに一致するルートにのみCORSヘッダーを付与します。404または未登録ルートにアクセスした場合、CORSミドルウェアは実行されず、設定が正しく見えるにもかかわらず「ヘッダーが存在しない」というエラーが表示されます。まず有効なエンドポイントでテストしてください。 Access-Control-Allow-Origin 必要な場合、サーバーが返すべき正確なCORSヘッダーを生成するには、
IO Tools CORSヘッダー生成ツール
を使用できます。オリジン、メソッド、認証情報を設定して、正確なヘッダーブロックを生成し、サーバー設定に貼り付けることができます。 セキュリティに関する補足 CORSはAPIセキュリティメカニズムではありません。設定
は、APIが公開されるという意味で攻撃面を拡大させません。curl、Postman、サーバー間呼び出しはCORS制限を受けません。ブラウザベースのJavaScriptのみが影響を受けます。APIが認証が必要な場合は、トークンまたはセッションを使ってAPIレベルで認証を実施してください。CORSヘッダーは、JavaScriptがどのオリジンから応答を読み取ることができるかをブラウザに伝えます。これは実際のアクセス制御とは関係ありません。
この文脈を理解した上で、CORS設定について合理的な決定を下すことができます。無駄にセキュリティを強化しようとするのではなく、すべてを閉じたり、理解せずにすべてを開くのではなく、そのトレードオフを理解した上で判断できるようになります。 Access-Control-Allow-Origin: * CORSを説明:クロスオリジンエラーをデバッグするための手順(2)
CORSを説明:クロスオリジンエラーをデバッグするための手順(1)
