CORSとは?仕組みからエラー解決方法まで徹底解説 (Access-Control-Allow-Origin)
Web開発をしていると、ブラウザのコンソールで以下のような赤いエラーメッセージに遭遇したことが一度はあるのではないでしょうか。
Access to fetch at 'https://api.example.com/data' from origin 'https://my-app.com' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
「自分のサーバーからデータを取得したいだけなのに、なぜブロックされるの?」と疑問に思う方も多いかもしれません。
このエラーの原因である CORS (Cross-Origin Resource Sharing) は、Webブラウザの重要なセキュリティ機能の一つです。
本記事では、CORSの基本的な概念から、なぜこのエラーが発生するのか、そしてどのように解決すればよいのかを、QiitaやZennの読者の皆様に向けて技術的に深掘りして解説します。
CORS (Cross-Origin Resource Sharing) とは
CORS(オリジン間リソース共有) とは、あるオリジン(ドメイン、スキーム、ポート)で動作しているWebアプリケーションが、異なるオリジンのサーバーにあるリソースにアクセスする権限を与えるための仕組みです。
同一オリジンポリシー (Same-Origin Policy: SOP)
前提として、ブラウザには 同一オリジンポリシー (SOP) というセキュリティルールが存在します。
これは、「あるオリジンから読み込まれた文書やスクリプトが、許可なしに他のオリジンのリソースにアクセスできないようにする」というものです。
例えば、悪意のあるサイト evil.com が、ユーザーがログイン中の bank.com に対して勝手にAPIリクエストを送ることを防ぐためにあります。
しかし、現代のWeb開発では、フロントエンド(例: localhost:3000)とバックエンド(例: localhost:8080)が異なるオリジンで構成されることが一般的です。
そこで、「このリクエストは安全だから許可してほしい」とブラウザに伝えるためのメカニズムが必要となり、それが CORS です。
CORSの動作メカニズム
CORSは、HTTPヘッダーを使用してブラウザとサーバー間でやり取りを行います。
1. 単純リクエスト (Simple Request)
以下の条件を満たすリクエストは「単純リクエスト」と呼ばれ、プリフライトリクエストなしで送信されます。
- メソッドが
GET,HEAD,POSTのいずれか - ヘッダーが
Accept,Content-Type(一部の値のみ) など、安全なものに限られる場合
ブラウザはリクエストに Origin ヘッダーを付与します。
GET /api/data HTTP/1.1 Origin: https://my-app.com
サーバーがこのオリジンを許可する場合、レスポンスに Access-Control-Allow-Origin を含めます。
HTTP/1.1 200 OK Access-Control-Allow-Origin: https://my-app.com
2. プリフライトリクエスト (Preflight Request)
PUT や DELETE メソッドを使用する場合や、Authorization ヘッダー、Content-Type: application/json などを送信する場合は、ブラウザは実際のリクエストを送る前に、「このリクエストを送っても良いか?」 を確認する予備リクエストを送信します。これを プリフライトリクエスト と呼び、OPTIONS メソッドが使われます。
ブラウザ (Preflight):
OPTIONS /api/data HTTP/1.1 Origin: https://my-app.com Access-Control-Request-Method: POST Access-Control-Request-Headers: content-type
サーバー (レスポンス):
HTTP/1.1 204 No Content Access-Control-Allow-Origin: https://my-app.com Access-Control-Allow-Methods: POST, GET, OPTIONS Access-Control-Allow-Headers: content-type
サーバーから許可が得られて初めて、ブラウザは本番のリクエストを送信します。
よくあるCORSエラーと解決策
エラー1: "No 'Access-Control-Allow-Origin' header is present"
最も一般的なエラーです。サーバーからのレスポンスに Access-Control-Allow-Origin ヘッダーが含まれていない、または許可リストに現在のオリジンが含まれていない場合に発生します。
解決策:
バックエンド側の設定を変更する必要があります。(フロントエンドだけで解決することは基本的にできません)
- Node.js (Express):
corsミドルウェアを使用します。const cors = require('cors'); app.use(cors({ origin: 'https://my-app.com', // 特定のドメインのみ許可 credentials: true, })); - Go (Gin):
github.com/gin-contrib/corsを使用します。
エラー2: ワイルドカード '*' と Credentials の競合
withCredentials: true (Cookieや認証情報を含むリクエスト) を送信する場合、サーバー側で Access-Control-Allow-Origin: * (すべて許可) を設定することはセキュリティ上禁止されています。
解決策:
サーバー側で、リクエスト元のオリジンを明示的に指定して返す必要があります。
Access-Control-Allow-Origin: https://my-app.com Access-Control-Allow-Credentials: true
エラー3: ローカル開発環境でのCORSエラー
開発中に毎回バックエンドの設定を変更するのは手間がかかります。
解決策: プロキシ (Proxy) の利用
Vite, Next.js, Create React App などの開発サーバーには、プロキシ機能が組み込まれています。
これを利用すると、ブラウザは「同じオリジン(開発サーバー)」にリクエストを送っていると認識し、開発サーバーがバックエンドにリクエストを転送するため、CORSエラーを回避できます。
// vite.config.js の例 export default { server: { proxy: { '/api': { target: 'http://localhost:8080', changeOrigin: true, }, }, }, };
まとめ
CORSは開発者にとって厄介な存在に思えるかもしれませんが、Webのセキュリティを守るための重要な防壁です。
仕組みを正しく理解していれば、エラーが発生しても慌てずにサーバー側の設定やリクエストヘッダーを確認することで、スムーズに解決できるはずです。
もし、API開発中にJSONデータのフォーマット確認やバリデーションが必要になった際は、Pockitの JSONフォーマッター & バリデーター をぜひ活用してみてください。構文エラーのチェックに役立ちます。
本記事が皆様の開発の一助となれば幸いです。
関連ツールを見る
Pockitの無料開発者ツールを試してみましょう