プログラミング ソフトウェア 公開日 2026.04.04 更新日 2026.04.04

CORSとは?初心者がつまずきやすい原因と考え方をわかりやすく解説

CORSとは何か、なぜエラーになるのか、何を許可すべきなのか、初心者がつまずきやすい考え方を整理した記事です。

先に要点

  • CORS は、ブラウザが別オリジンへのリクエストをどう扱うかを決める仕組みです。
  • よくある CORS エラーは、API が壊れているというより `ブラウザが止めている` ケースがかなり多いです。
  • `とりあえず全部許可` は危ないので、どの Origin を、どのメソッドやヘッダーで許可するのか整理して考える必要があります。

フロントエンドから API を呼んだら CORS エラーが出たけど、何が悪いのか分からない というのはかなりよくあるつまずきです。
しかも、初心者のうちは サーバーエラーブラウザの制約 が混ざって見えやすいので、さらに分かりにくくなります。

この記事では、2026年4月4日時点で MDN の CORS ガイド、Preflight request の説明、WHATWG Fetch Standard の CORS まわりを確認しながら、CORS とは何か、なぜエラーになるのか、どう考えると整理しやすいのかを初心者向けにまとめます。
フロントエンドと API を分ける構成の全体像から見たいなら、代表的なフレームワーク7選|Laravel・Django・Rails・Spring Boot・Next.js・Nuxt・FastAPIの向いている用途を比較 もつながりやすいです。

CORSとは何か

CORSCross-Origin Resource Sharing の略で、ブラウザが別オリジンへのリクエストをどう許可するかを決める仕組みです。
MDN でも、追加の HTTP ヘッダーによって、あるオリジンで動く Web アプリが別オリジンのリソースへアクセスできるかをブラウザへ伝える仕組みと説明されています。

ここで先に押さえたいのは、CORS はブラウザの仕組み だということです。
つまり、curl やサーバー間通信では通るのに、ブラウザだけ失敗することがあります。

そもそも「オリジン」とは何か

Origin は、ざっくり言うと スキーム + ホスト + ポート の組み合わせです。

たとえば、

  • https://example.com
  • https://api.example.com
  • http://example.com
  • https://example.com:8443

は、それぞれ別オリジンとして扱われることがあります。

このため、

  • フロントは http://localhost:3000
  • APIhttp://localhost:8000

のような開発構成でも、ブラウザから見ると別オリジンです。
ここで CORS が出やすくなります。

なぜそんな制限があるのか

背景にあるのは Same-Origin Policy です。
これは、あるサイト上で動くスクリプトが、別オリジンの応答を自由に読めないようにするブラウザの基本制約です。

もしこれがなければ、悪意あるサイトを開いただけで、別サイトの情報が勝手に読まれる危険が高くなります。
そのため、同一オリジン以外は原則そのまま読ませない をベースにして、必要なときだけ CORS で許可する形になっています。

どういうときに CORS エラーになるのか

初心者がハマりやすいのは、リクエスト自体は飛んでいるのに、ブラウザでだけ読めない パターンです。

たとえば次のような場面です。

  • http://localhost:3000 の画面から http://localhost:8000/api を呼ぶ
  • https://app.example.com から https://api.example.com を呼ぶ
  • JavaScriptfetch() や Axios で別オリジンの API を叩く

このとき、サーバーが適切な CORS ヘッダーを返していないと、ブラウザは応答をアプリ側へ渡しません。

まずよくある誤解

API が 200 を返していても CORS で失敗することがある

ここはかなり大事です。
ネットワークタブを見ると 200 に見えるのに、JavaScript 側ではエラーになることがあります。

これは、HTTP 応答そのものは返っていても、ブラウザが このオリジンには読ませない と判断しているからです。
つまり、バックエンド処理と CORS 判定は別の話です。

「サーバー間通信」には CORS は関係ない

サーバーからサーバーへ API を呼ぶだけなら、普通は CORS は関係しません。
ブラウザで動く JavaScript が別オリジンへ取りに行くときに問題になりやすいです。

no-cors を付ければ解決するわけではない

fetch()mode: 'no-cors' を見つけて、これで解決できると思う人も多いです。
ただ、このモードは 読める普通の API 応答を得る ための解決策ではありません。
初心者が 画面から API の JSON を受け取りたい 場面では、ほぼ期待どおりに使えないと考えた方が安全です。

Preflight request とは何か

ブラウザは、いきなり本番のリクエストを送る前に、このリクエスト送ってよい? と確認することがあります。
これが Preflight request です。

典型的には、

  • Content-Type: application/json を付ける
  • Authorization ヘッダーを付ける
  • PUT PATCH DELETE を使う

ような場面で、先に OPTIONS リクエストが飛びます。

この preflight に対してサーバーが正しく返せないと、実際の本リクエストまで進みません。
初心者が POST なのに OPTIONS が見える と戸惑いやすいのはこのためです。

何を許可するのか

CORS では、主に次を整理します。

  • どの Origin からのアクセスを許可するか
  • どの HTTP メソッドを許可するか
  • どのヘッダーを許可するか
  • Cookie や認証情報を含めるか

特によく見るのが Access-Control-Allow-Origin です。
これは、どのオリジンを許可するかをブラウザへ伝えるヘッダーです。

初心者向けの考え方

実務では、CORS を有効にする ではなく、どの画面からどの API を呼ばせたいのか を先に決めます。

たとえば、

  • フロント: https://app.example.com
  • API: https://api.example.com

なら、API 側で https://app.example.com を許可対象にします。

ここで雑に * を返すと、開発中は動いても、あとで認証や Cookie を含めたときに困りやすいです。
特に credentials: 'include' を使う構成では、ワイルドカードで済まないことがあります。

つまずきやすい原因

1. フロントと API のポートが違う

ローカル開発ではこれがかなり多いです。
localhost が同じでも、ポートが違えば別オリジンになることがあります。

2. preflight の OPTIONS を処理していない

本体の POST /api/... は作ったのに、OPTIONS への返しが足りず、ブラウザだけ止まるパターンです。

3. 許可オリジンを雑にしすぎる or 絞りすぎる

* にしてしまってあとで認証情報とぶつかる、逆に本番ドメインを入れ忘れる、というのはかなりよくあります。

4. CORS と認証エラーが混ざって見える

401 や 403 と CORS が同時に出ると、どちらが本当の原因か見えにくくなります。
まずはネットワークタブで、サーバー応答そのものブラウザの CORS 判定 を分けて見るのが大事です。

どう確認するとよいか

初心者向けには、次の順で見ると整理しやすいです。

  1. リクエスト元の画面URLを確認する
  2. 呼んでいる API の URL を確認する
  3. オリジンが違うかを見る
  4. ネットワークタブで OPTIONS が飛んでいないか見る
  5. 応答ヘッダーに Access-Control-Allow-Origin などがあるか見る
  6. 401/403/500 と CORS を混同していないか見る

この順に分けるだけで、かなり迷いにくくなります。

実務でどう考えるか

実務では、CORS は とりあえず動けばよい設定 にしない方が安全です。
フロントと API を分ける構成ではかなり普通に出てくるので、最初から 許可するオリジン を設計に入れておく方が後で崩れにくいです。

特に次のような場面で重要です。

  • フロントと API を別ドメイン・別サブドメインで分ける
  • Next.jsNuxt の画面から別 API を呼ぶ
  • 管理画面と公開APIを分離する
  • 認証付きの API をブラウザから使う

まとめ

CORS は、ブラウザが別オリジンのリクエストをどう扱うかを決める仕組みです。
大事なのは、CORS エラーは API が壊れた のではなく、ブラウザが読ませていない ことが多いと分けて考えることです。

そのうえで、OriginSame-Origin PolicyPreflight request を押さえると、かなり見通しがよくなります。
初心者のうちは、どの画面からどの API を呼ばせたいのか を先に整理して、サーバー側で必要な範囲だけ許可する考え方で進めるのがいちばん分かりやすいです。

参考情報

あとで見返すならここで保存

読み終わったあとに残しておきたい記事は、お気に入りからまとめて辿れます。