markdown

はじめに (対象読者・この記事でわかること)

この記事は、Webフロントエンド開発者やJavaScriptで外部APIを利用したいエンジニアを対象としています。同一生成元ポリシー(Same‑Origin Policy)の制約に悩んだことがある方へ、CORS(Cross‑Origin Resource Sharing)という仕組みが何であるか、ブラウザがどのようにリクエストを判定するか、サーバ側での設定方法までを体系的に理解できるよう解説します。実際にコード例を交えて設定手順を示すので、すぐに自分のプロジェクトに適用できるはずです。また、CORSエラーの原因診断やよくある落とし穴の回避策も併せて紹介します。この記事を読むだけで、CORSに関する基礎知識と実装の全体像が掴め、開発効率が向上します。

前提知識

この記事を読み進める上で、以下の知識があるとスムーズです。
- HTML・JavaScript の基本的な知識
- HTTP ステータスコードとヘッダーの概要

CORSポリシーの概要と必要性

Webブラウザは、セキュリティ上の理由から「同一生成元ポリシー」を適用し、スクリプトが自分のオリジン(プロトコル・ホスト・ポート)が一致しないリソースに直接アクセスすることを禁止します。この制限は、クロスサイトスクリプティング(XSS)や情報漏洩を防ぐための重要な防御線です。一方で、モダンなWebアプリはSNSのシェアボタンや外部分析サービス、クラウドAPIなど、複数のオリジン間でデータをやり取りするケースが増えています。そこで登場したのが「Cross‑Origin Resource Sharing(CORS)」です。CORSは、サーバが特定のオリジンからのリクエストを許可する旨をHTTPヘッダーで明示し、ブラウザはその指示に従ってリソースの受け渡しを許可します。つまり、サーバ側が「どのオリジンからのアクセスを許可するか」を宣言することで、同一生成元ポリシーを緩めつつも安全性を保てる仕組みです。

実装ステップ:CORSを正しく設定して安全に通信する

ステップ1 プリフライトリクエストの仕組みを理解する

GET/POST 以外のメソッドや、Content-Typeapplication/json のように非簡易リクエストヘッダーを伴う場合、ブラウザはまず OPTIONS メソッドで「プリフライト」リクエストを送ります。サーバは次のヘッダーを返す必要があります。

ヘッダー 目的
Access-Control-Allow-Origin 許可するオリジン(* でも可)
Access-Control-Allow-Methods 許可する HTTP メソッド (GET,POST,PUT,DELETE など)
Access-Control-Allow-Headers 許可するリクエストヘッダー (Content-Type,Authorization など)
Access-Control-Max-Age プリフライト結果のキャッシュ時間(秒)

この段階でサーバが正しいヘッダーを返さないと、ブラウザは実際のリクエスト自体をブロックします。

ステップ2 サーバ側で CORS ヘッダーを付与する(Node.js/Express の例)

Js
// server.js const express = require('express'); const app = express(); const corsOptions = { origin: ['https://example.com', 'http://localhost:3000'], // 許可したいオリジンの配列 methods: ['GET','POST','PUT','DELETE','OPTIONS'], allowedHeaders: ['Content-Type','Authorization'], credentials: true, // Cookie や Authorization ヘッダーを送信したい場合 maxAge: 86400 // 24時間キャッシュ }; app.use((req, res, next) => { const origin = req.headers.origin; if (corsOptions.origin.includes(origin)) { res.setHeader('Access-Control-Allow-Origin', origin); } res.setHeader('Access-Control-Allow-Methods', corsOptions.methods.join(',')); res.setHeader('Access-Control-Allow-Headers', corsOptions.allowedHeaders.join(',')); if (corsOptions.credentials) { res.setHeader('Access-Control-Allow-Credentials', 'true'); } if (req.method === 'OPTIONS') { res.setHeader('Access-Control-Max-Age', corsOptions.maxAge); return res.sendStatus(204); } next(); }); app.get('/api/data', (req, res) => { res.json({ message: 'CORS が正しく設定されています' }); }); app.listen(4000, () => console.log('Server running on http://localhost:4000'));

ポイント
1. 動的に Origin を設定* を使うと credentials:true が無効になるため、許可したオリジンだけを列挙します。
2. OPTIONS ハンドリング:プリフライトリクエストに対しては 204 No Content を返すだけで OK。
3. Credentials:フロントエンドが Cookie や HTTP 認証情報を送る場合は Access-Control-Allow-Credentials:true が必須です。

ステップ3 フロントエンド側で fetch / XMLHttpRequest を呼び出す例

Js
// client.js const url = 'http://localhost:4000/api/data'; fetch(url, { method: 'GET', credentials: 'include' // Cookie を送信したいとき }) .then(res => { if (!res.ok) throw new Error('Network response was not ok'); return res.json(); }) .then(data => console.log(data)) .catch(err => console.error('CORS エラーかその他の問題:', err));

credentials: 'include' を指定した場合、サーバ側の Access-Control-Allow-Credentials:true が必須になる点に注意してください。

ハマった点やエラー解決

症状 原因 解決策
No 'Access-Control-Allow-Origin' header is present on the requested resource. サーバが Access-Control-Allow-Origin を返していない。 オリジン検証ロジックを確認し、許可リストに対象オリジンが入っているか確認。
Response to preflight request doesn’t pass access control check: It does not have HTTP ok status. プリフライトで 200 系以外(例: 404, 500, 403)が返っている。 OPTIONS 用のハンドラを正しく実装し、204 No Content を返すようにする。
Credential is not supported if the CORS header ‘Access-Control-Allow-Origin’ is ‘*’ Access-Control-Allow-Origin:*credentials:true が同時に設定されている。 * をやめ、実際のリクエスト元を動的に設定する。
Request header field X-Requested-With is not allowed by Access‑Control‑Allow‑Headers フロント側が独自ヘッダーを送っているがサーバ側で許可していない。 Access-Control-Allow-Headers に該当ヘッダー名を追加。

解決策のベストプラクティス

  1. オリジンはできるだけ絞る* を乱用するとセキュリティリスクが高まります。
  2. 環境変数で設定を管理:本番・ステージング・ローカルで許可リストが変わることが多いので、.env に保存しコードから参照するようにするとミスが減ります。
  3. ログでプリフライト失敗を追跡:サーバ側で OPTIONS が来たときのステータスコードとヘッダーをログに残すと、原因特定が容易です。

まとめ

本記事では、CORS の基本概念とブラウザがリクエストを制御する仕組み、Node.js/Express でのサーバ設定例、フロントエンドからの正しい呼び出し方、そして実装中に遭遇しやすいエラーとその対策を詳しく解説しました。

  • CORS はサーバ側が許可オリジンを宣言することで同一生成元ポリシーを緩和する仕組み
  • プリフライト (OPTIONS) の正しいハンドリングが成功の鍵
  • Credentials を使う場合は Origin の動的指定とヘッダーの厳密な設定が必要

これらを実装すれば、外部 API との安全な通信が実現し、開発効率とユーザー体験が向上します。次回は、Cloudflare Workers や AWS API Gateway での CORS 設定についても取り上げる予定です。

参考資料