JavaScript | Web API:通信・ネットワーク系 - CORS の基本

JavaScript JavaScript
スポンサーリンク

まず「なぜ CORS なんてものがあるのか」から

CORS を理解する一番の近道は、
「ブラウザは、もともと“よそのサイトに勝手にリクエストさせない”ように作られている
という前提をちゃんと掴むことです。

もし制限がなかったらどうなるか想像してみてください。

あなたが https://evil.com を開いた瞬間、そのページの JavaScript が勝手に
https://bank.example.com にログイン済みクッキー付きでリクエストを送り、
残高情報や個人情報を盗み放題——という世界になります。

それを防ぐためにあるのが「同一オリジンポリシー」です。
そして、その制限を“安全を保ったまま一部ゆるめる仕組み”が CORS(Cross-Origin Resource Sharing) です。


同一オリジンポリシーと「オリジン」の意味

オリジンとは何か

CORS の話をする前に、「オリジン」という言葉を押さえます。

オリジンは、
「プロトコル + ドメイン + ポート」の組み合わせ です。

例えば、次は全部別オリジンです。

https://example.com
http://example.com(http と https が違う)
https://api.example.com(サブドメインが違う)
https://example.com:8080(ポートが違う)

ブラウザは、
「あるオリジンで動いている JavaScript が、別オリジンのデータを勝手に読めないようにする」
というルールを持っています。これが同一オリジンポリシーです。

何が制限されるのか

ここが少しややこしいのですが、
「リクエストを送ること」自体は、わりと自由にできます。

例えば、<img src="..."><script src="..."> は、
別オリジンでも普通に動きます。

制限されるのは主に、
「JavaScript から、別オリジンのレスポンスの中身を読むこと」 です。

fetch で別オリジンにリクエストを送っても、
CORS が許可されていなければ、ブラウザは「中身を JS に渡さない」ようにします。


CORS は「サーバー側が OK を出す仕組み」

「このオリジンからのアクセスは読んでいいよ」とサーバーが宣言する

CORS の本質はこれです。

「サーバー側が、特定のオリジンからのアクセスを許可するかどうかをヘッダーで宣言する仕組み」

代表的なのが Access-Control-Allow-Origin ヘッダーです。

例えば、サーバーがレスポンスにこう付けます。

Access-Control-Allow-Origin: https://example.com

これは、

https://example.com で動いている JavaScript からのリクエストなら、
このレスポンスの中身を読んでいいよ」

という意味になります。

もしここが * なら、

Access-Control-Allow-Origin: *

「どのオリジンからでも読んでいいよ」という意味になります(ただし制限もある)。

重要:CORS を決めるのは「サーバー側」

初心者が一番ハマるポイントがここです。

ブラウザ側(フロントエンド)からは、
CORS を「有効にする」ことはできません。

できるのは「CORS に引っかからないようなリクエストの仕方をする」くらいで、
「このレスポンスを他オリジンから読んでいいかどうか」を決めるのは、
あくまでサーバー側です。

だから、ローカルで fetch("http://localhost:3000") して CORS エラーが出たとき、
フロント側のコードをいじっても根本解決にはなりません。
サーバー側の CORS 設定を変える必要があります。


実際に何が起きているのか(シンプルなケース)

シンプルな GET リクエストの流れ

例えば、フロントが http://localhost:5173、API が http://localhost:3000 だとします。
これは別オリジンです。

フロント側でこう書きます。

fetch("http://localhost:3000/api/users")
  .then((res) => res.json())
  .then(console.log)
  .catch(console.error);
JavaScript

ブラウザは API にリクエストを送ります。
サーバーがレスポンスを返します。

そのとき、レスポンスヘッダーに

Access-Control-Allow-Origin: http://localhost:5173

が付いていれば、
ブラウザは「よし、このオリジンからの読み取りは許可されているな」と判断し、
JavaScript にレスポンスの中身を渡します。

もしこのヘッダーがなければ、
ブラウザは「レスポンスは受け取ったけど、中身は JS に渡さない」と判断し、
コンソールに CORS エラーを出します。

ここで大事なのは、
「リクエスト自体は飛んでいる」 ということです。
CORS は「レスポンスを JS から読ませるかどうか」の制御です。


プリフライトリクエスト(OPTIONS)という一手間

「ちょっと事前に確認させて」のリクエスト

CORS には、もう一つよく出てくる概念があります。
それが プリフライトリクエスト(preflight) です。

ある種のリクエスト(例えば、カスタムヘッダー付きの POST など)を送る前に、
ブラウザが自動的に「事前確認」のリクエストを送ります。

それが OPTIONS メソッドのリクエストです。

流れとしてはこうです。

ブラウザ
「このオリジンから、こういうメソッド・ヘッダーでリクエストしてもいい?」
(OPTIONS リクエストを送る)

サーバー
「いいよ、そのメソッドとヘッダーは許可するよ」
Access-Control-Allow-OriginAccess-Control-Allow-Methods などを返す)

ブラウザ
「OK、じゃあ本番のリクエスト送るね」
(本来の POST / PUT などを送る)

この「事前確認」がプリフライトです。

どんなときにプリフライトが走るのか

ざっくり言うと、

「安全とみなされるシンプルなリクエスト」以外のときにプリフライトが走ります。

例えば、
Content-Typeapplication/json の POST
カスタムヘッダー(X-... など)を付けたリクエスト
PUT / DELETE などのメソッド

などです。

初心者としては、
「なんか OPTIONS が勝手に飛んでるな…」と思ったら、
「これはブラウザが CORS の事前確認をしているんだ」と理解できれば十分です。


フロントエンドから見た「CORS エラー」とどう付き合うか

典型的なエラーメッセージ

ブラウザのコンソールに、こんな感じのエラーが出ます。

Access to fetch at ‘http://localhost:3000/api/users’ from origin ‘http://localhost:5173’ has been blocked by CORS policy: No ‘Access-Control-Allow-Origin’ header is present on the requested resource.

これは要するに、

「サーバーのレスポンスに Access-Control-Allow-Origin が付いてないから、
このオリジンからは読ませないよ」

と言われている状態です。

フロント側でできること・できないこと

できないこと
フロント側の JavaScript だけで CORS を「無効化」すること
ブラウザのセキュリティルールをねじ曲げること

できること
サーバー側の CORS 設定を変えてもらうように伝える
開発中だけ、プロキシサーバーを立てて同一オリジンに見せかける
(Vite や webpack dev server の proxy 設定など)

大事なのは、
「CORS はブラウザとサーバーの約束事であって、フロントだけでは完結しない」
という理解です。


初心者として CORS で本当に掴んでほしいこと

ざっくりまとめると

同一オリジンポリシー
ブラウザは、別オリジンのレスポンスを JS から自由に読ませないことで、
ユーザーを守っている。

CORS
その制限を、サーバー側の明示的な許可がある場合にだけ緩める仕組み。
Access-Control-Allow-Origin などのヘッダーで制御する。

決めるのはサーバー側
フロント側から「CORS を ON にする」ことはできない。
サーバーが「このオリジンからのアクセスは読んでいい」と宣言する必要がある。

プリフライト
一部のリクエストでは、ブラウザが事前に OPTIONS で「これ送っていい?」と聞きに行く。
それに対するサーバーの返事次第で、本番リクエストが送られるか決まる。

いい練習の仕方

一番おすすめなのは、
ローカルでフロント(http://localhost:5173)と API(http://localhost:3000)を別々に立てて、
わざと CORS エラーを出してみることです。

そのうえで、

サーバー側に Access-Control-Allow-Origin: * を付けたらどう変わるか
特定のオリジンだけ許可したらどうなるか
プリフライト(OPTIONS)がいつ飛ぶか

を、ネットワークタブとコンソールを見ながら確認してみてください。

CORS は「エラー文だけ見ていると意味不明」ですが、
一度「ブラウザがユーザーを守るための仕組み」という軸で理解できると、
ただの邪魔者ではなく、「ちゃんと理由のあるガード」 に見えてきます。

タイトルとURLをコピーしました