fetchでCORSエラーが出る原因と解決法まとめ|初心者でもわかる仕組みと対処法

javascript
記事内に広告が含まれています。

Webアプリ開発でAPIを利用する際に、fetch を使った瞬間に「CORS policy に違反しています」「No ‘Access-Control-Allow-Origin’ header is present」といった見慣れないエラーが表示され、作業がストップしてしまった経験はありませんか?

ローカル環境では動いたのに本番ではエラー、他のAPIでは取得できるのに特定のAPIだけダメ、といった状況に直面すると「一体どこを直せばいいのか…」と混乱してしまいます。特に納期が迫っていると、焦ってググっても断片的な情報しか見つからず、余計に時間を浪費してしまうことも多いです。

CORS(クロスオリジンリソースシェアリング)は、ブラウザがセキュリティを守るために設けている仕組みです。しかし開発者にとっては「なぜブロックされるのか」「どのように設定すれば許可できるのか」を正しく理解しておかないと、いつまでも同じエラーに悩まされることになります。

この記事では、「fetchとCORSエラー」の仕組みと原因、そして現場ですぐに使える具体的な解決方法を整理しました。axiosや外部API、Docker環境などケース別の対処法もまとめていますので、この記事を読み終える頃には「CORSでつまずかない自分」になれるはずです。

この記事を読んでわかること

  • CORSの基本的な仕組みと、なぜブラウザが制約を課しているのか
  • fetchを使ったときにCORSエラーが発生する3つの典型的な原因
  • fetchとaxiosでの挙動の違いと、それぞれの対処方法
  • ローカル開発環境でCORSエラーを回避する方法(proxy設定やブラウザ拡張の活用)
  • mode: 'cors'mode: 'no-cors' の違いと正しい使い分け方
  • Google Maps APIやAWS API Gatewayなど外部APIを呼び出す際の注意点と解決策
  • Preflightリクエスト(OPTIONS)の仕組みとエラーの原因
  • Dockerや社内API環境でよくあるCORSトラブルの対処法
  • 今後同じエラーに遭遇したときに自走して解決できるための知識とベストプラクティス

この記事を通して、単なる「一時的な回避」ではなく、セキュリティを理解したうえで正しくCORSを扱える力を身につけましょう。

Webデザインコース

fetchで発生するCORSエラーとは?基本の仕組みと原因

CORSの概要とブラウザのセキュリティ制約

Web開発中にfetchを使ってAPIからデータを取得しようとした際、ブラウザのコンソールに「CORS policy: No ‘Access-Control-Allow-Origin’ header is present on the requested resource」といった見慣れないエラーメッセージが表示された経験はありませんか? これはCORS(Cross-Origin Resource Sharing)というブラウザのセキュリティ機能によるものです。

CORSは、異なる「オリジン」間でリソース(データ)を安全にやり取りするための仕組みです。ここでいうオリジンとは、ウェブサイトのアドレスを構成する以下の3つの要素の組み合わせを指します。

ウェブサイトのアドレスを構成する3つの要素

  1. プロトコルhttp:またはhttps:
  2. ホスト(ドメイン名。例:example.com
  3. ポート番号(例::8080

たとえば、https://www.example.comhttps://api.example.comはホストが異なるため、別のオリジンとみなされます。ブラウザは、この「同一オリジンポリシー」というセキュリティルールに基づき、異なるオリジンへのHTTPリクエストを原則としてブロックします。これは、悪意のあるサイトがユーザーの情報を盗み取ることを防ぐための重要な仕組みです。

CORSはこの同一オリジンポリシーを緩和し、サーバー側が許可した場合に限り、異なるオリジンからのアクセスを許可するものです。しかし、サーバー側がCORSを正しく設定していないと、ブラウザはこのセキュリティルールに従ってリクエストをブロックし、結果としてCORSエラーが発生するのです。

Window: fetch() メソッド - Web API | MDN
fetch() は Window インターフェイスのメソッドで、ネットワークからリソースを取得するプロセスを開始し、レスポンスが利用できるようになったら履行されるプロミスを返します。
現役エンジニアのパーソナルメンターからマンツーマンで学べるテックアカデミー

fetchでCORSエラーが発生する3つの原因

fetchでCORSエラーが発生する主な原因は、大きく分けて以下の3つです。

  1. サーバー側がCORSを許可していない
    これが最も一般的な原因です。APIを提供しているサーバーが、リクエスト元のオリジンからのアクセスを許可するためのAccess-Control-Allow-Originヘッダーを設定していないか、正しく設定されていません。
  2. 複雑なリクエスト(プリフライトリクエスト)が失敗している
    POSTやPUTメソッドを使ったり、カスタムヘッダーを付与したりする「複雑なリクエスト」の場合、ブラウザは本番のリクエストを送る前に、まずOPTIONSメソッドを使った「プリフライトリクエスト」をサーバーに送信します。サーバーがこのOPTIONSリクエストに正しく応答しないと、本番のリクエストは送られずCORSエラーになります。
  3. 認証情報(Cookieなど)を正しく扱えていない
    fetchでCookieなどの認証情報を送信する場合、credentials: 'include'オプションが必要です。また、サーバー側もAccess-Control-Allow-Credentials: trueヘッダーと特定のオリジンを許可する設定が必要です。これらの設定に不整合があると、エラーになります。

エラーメッセージが「Access-Control-Allow-Origin」に関連するものであれば、多くの場合、原因1か2に該当します。

fetch特有の挙動とaxiosなど他のHTTPクライアントとの違い

fetchは、JavaScriptに標準で組み込まれているAPIであり、シンプルでモダンなリクエスト送信が可能です。一方で、axiosは外部ライブラリであり、より豊富な機能と自動的なエラーハンドリングを備えています。

CORSエラーに関して言えば、両者の本質的な挙動に違いはありません。なぜなら、どちらもブラウザの同一オリジンポリシーに準拠して動作しているからです。fetchでCORSエラーが出るときは、axiosでもほぼ確実に同じエラーが発生します。

しかし、axiosは便利な自動変換や設定のデフォルト化(例えばJSONデータの自動パース)など、開発者が意識すべき部分を減らしてくれるため、CORSの設定をよりシンプルに書ける場合があります。それでも、エラーの根本原因は常にサーバー側の設定にあることを忘れてはなりません。

fetchでエラーに直面した際は、「なぜブラウザはリクエストをブロックするのか?」という根本的な問いに立ち返り、サーバーとクライアントの両方の視点から原因を探ることが解決への近道となります。

Axios
Webデザインコース

fetchでのCORSエラーを簡単に回避・対処する具体的方法

ローカル開発環境でのCORSエラー回避方法

ローカルで開発しているときにだけCORSエラーが発生する場合、本番環境のAPIにアクセスするための簡単な回避策がいくつかあります。

1. プロキシサーバーを利用する

最も一般的な解決策は、開発サーバーにプロキシ設定を追加することです。これにより、フロントエンドからのAPIリクエストが、一度開発サーバーを経由してバックエンドに転送されます。このとき、ブラウザから見るとリクエストは同じオリジン内で行われているように見えるため、CORSエラーを回避できます。

create-react-appの場合

package.jsonファイルに以下の1行を追加するだけで、簡単にプロキシを設定できます。

JSON

"proxy": "<http://localhost:8080>"

これにより、fetch('/api/users')のようなリクエストは、自動的にhttp://localhost:8080/api/usersへ転送されます。

Vue CLIやViteの場合

vue.config.jsやvite.config.jsに、より詳細なプロキシ設定を記述します。

JavaScript

// vue.config.js
module.exports = {
  devServer: {
    proxy: '<http://localhost:8080>'
  }
}

2. ブラウザの拡張機能を使う

開発中の一時的な確認であれば、ブラウザの拡張機能を利用する手もあります。「CORS Unblock」のような拡張機能を有効にすると、ブラウザのセキュリティ設定を一時的に無効化し、CORSエラーを無視してリクエストを通すことができます。ただし、これはあくまで開発中のデバッグ用であり、本番環境での解決策にはなりません。

現役エンジニアのパーソナルメンターからマンツーマンで学べるテックアカデミー

mode: 'cors' と mode: 'no-cors' の違いと使い分け

fetch APIにはmodeというオプションがあり、リクエストがどのように扱われるかを指定できます。

mode: ‘cors’(デフォルト)

異なるオリジンへのリクエストを許可しますが、CORSポリシーに従ってサーバーが適切なヘッダーを返さないとエラーになります。通常、APIからJSONデータなどを取得する場合はこのモードを使用します。

JavaScript

fetch('https://api.example.com/data', {
  method: 'GET',
  mode: 'cors' // デフォルトなので省略可
});

▼mode: ‘no-cors’

異なるオリジンへのリクエストを「隠蔽」します。リクエスト自体は送信されますが、ブラウザはレスポンスヘッダーを読み取ることができません。そのため、response.json()などでレスポンスボディを扱うことができず、実質的にAPIからのデータ取得には使えません。 このモードは、主に<img>タグや<link>タグのように、レスポンス内容をJavaScriptで操作しない単純なリソースの取得に限定して使用します。CORSエラーを回避するためにこのモードを使っても、JSONデータなどを取得することはできないため、ほとんどの場合、解決策にはなりません。

axiosでのCORSエラー対処例とfetchとの比較

axiosでもfetchと同様にCORSエラーは発生します。基本的な解決策(サーバー側の設定)は同じですが、axiosは設定ファイルでデフォルト値を管理できるため、CORSの認証情報などを一括で設定する際に便利です。

axiosでのCORS設定例

axiosでCookieなどの認証情報を送信する場合は、withCredentialsオプションをtrueに設定します。

JavaScript

axios.get('<https://api.example.com/data>', {
  withCredentials: true // Cookieを送信する
})
.then(response => {
  console.log(response.data);
})
.catch(error => {
  // CORSエラーもここでハンドリングされる
  console.error(error);
});

fetchの場合は、credentials: 'include'と書く必要があります。

共通の注意点

どちらのライブラリを使っても、CORSエラーの根本的な解決はサーバー側でのヘッダー設定にあります。プロキシ設定やブラウザ拡張機能はあくまで開発時の補助ツールであることを理解しておきましょう。本番環境では、サーバー側でAccess-Control-Allow-Originヘッダーを正しく設定することが必須となります。

Webデザインコース

ケース別CORSエラー対処法

Google Maps APIやAWS API Gatewayなど外部APIを呼び出す場合

外部サービスが提供するAPIを利用する際、CORSエラーは頻繁に発生します。これは、APIの提供元が意図的に特定のオリジンからのアクセスを制限しているためです。

この場合、自社のサーバー側でヘッダーを設定しても解決しません。API提供元の管理画面や設定ファイルで、リクエスト元のドメインを許可リストに追加する必要があります。

AWS API Gatewayの場合

API Gatewayのコンソール画面で、APIリソースを選択し、「CORSを有効化」ボタンをクリックします。ここで、Access-Control-Allow-Originヘッダーに(すべてのオリジンを許可)または特定のドメイン(例: https://your-domain.com)を設定します。

Firebase Functionsの場合

functions.https.onRequest内でcorsミドルウェアを使用します。

JavaScript

const functions = require('firebase-functions');
const cors = require('cors')({origin: true});

exports.yourApiFunction = functions.https.onRequest((request, response) => {
  cors(request, response, () => {
    // ... API処理 ...
  });
});

API提供元のドキュメントを必ず確認し、正しいCORS設定方法に従うことが重要です。

現役エンジニアのパーソナルメンターからマンツーマンで学べるテックアカデミー

Preflightリクエスト(OPTIONS)の仕組みとエラー原因

fetchPOSTPUTメソッドを使ったり、Authorizationヘッダーなどのカスタムヘッダーを付けたりする「複雑なリクエスト」を送信する場合、ブラウザは本番のリクエストに先立ってOPTIONSメソッドを使ったプリフライトリクエストを自動的に送信します。

このプリフライトリクエストは、サーバーに「この本番リクエストを送っていいか?」と事前に確認するためのものです。サーバーが以下のヘッダーを正しく返さないと、ブラウザは本番リクエストをキャンセルし、CORSエラーとして報告します。

  • Access-Control-Allow-Methods: 許可するメソッド(例: GET, POST, PUT
  • Access-Control-Allow-Headers: 許可するカスタムヘッダー(例: Authorization, Content-Type

対処法:

サーバー側のルーティングで、OPTIONSメソッドに対応するエンドポイントを作成し、上記ヘッダーを付与して204 No Contentなどのステータスコードを返すように設定します。多くのWebフレームワーク(Expressなど)では、CORSミドルウェアがこの処理を自動で行ってくれます。

Dockerや社内API環境でのCORS設定トラブル解決

ローカル開発環境でDockerコンテナを使ってAPIを動かす場合、コンテナのネットワーク設定や公開ポートが原因でCORSエラーが発生することがあります。

原因

フロントエンドがhttp://localhost:3000で、APIコンテナがhttp://localhost:8080で動いている場合、これらは異なるオリジンと見なされます。

対処法

docker-compose.ymlでポートを正しくマッピングする:

APIコンテナのポートがホストマシンに公開されているか確認します。

YAML

services:
  api-service:
    image: your-api-image
    ports:
      - "8080:8080" # ホスト:コンテナ

■APIサーバーのCORS設定を見直す

APIサーバーが、フロントエンドのオリジン(例: http://localhost:3000)からのリクエストを許可するように設定されているか確認します。

▼Express(Node.js)の場合:

corsミドルウェアを使って、許可するオリジンを指定します。

Javascript

const express = require('express');
const cors = require('cors');
const app = express();

// 特定のオリジンだけを許可
app.use(cors({
  origin: 'http://localhost:3000'
}));

// または、開発中だけすべてのオリジンを許可
// app.use(cors());

cors()を引数なしで使うとすべてのオリジンを許可しますが、本番環境ではセキュリティリスクがあるため、特定のオリジンを指定するようにしましょう。

◆◇◆ 【衝撃価格】VPS512MBプラン!1時間1.3円【ConoHa】 ◆◇◆

よくある質問(FAQ)

なぜローカル環境でだけCORSエラーが起こるのですか?

これは、開発環境と本番環境でオリジンが異なるためです。ローカル環境では、フロントエンドがhttp://localhost:3000、バックエンドがhttp://localhost:8080といったように、ポート番号が違うことがよくあります。ブラウザはこれを別々のオリジンと見なし、セキュリティ上の理由から通信をブロックします。一方、本番環境では、フロントエンドとバックエンドがhttps://example.comとhttps://api.example.comのようにサブドメインが異なっていても、サーバー側でCORSが適切に設定されていれば、通信が許可されるためエラーになりません。

サーバー側(例: Node.js, Express)でCORSヘッダーを追加する具体的なコードは?

最も簡単で推奨される方法は、corsというミドルウェアパッケージを使用することです。

1.まず、ターミナルでパッケージをインストールします。

Bash

npm install cors

2.次に、サーバーのコードに以下の数行を追加します。

JavaScript

const express = require('express');
const cors = require('cors');
const app = express();

// シンプルな使い方:すべてのオリジンからのリクエストを許可
app.use(cors());

// セキュリティを高める使い方:特定のオリジンからのリクエストのみ許可
// app.use(cors({
//   origin: 'https://your-frontend-domain.com'
// }));

app.get('/data', (req, res) => {
  res.json({ message: 'Hello CORS!' });
});

app.listen(8080, () => {
  console.log('Server is running on port 8080');
});

本番環境では、origin: 'https://your-frontend-domain.com'のように、許可するドメインを明示的に指定することがセキュリティ上のベストプラクティスです。

Access-Control-Allow-Origin: * はセキュリティ的に問題ないですか?

はい、基本的には問題があります*(ワイルドカード)を使用すると、世界中のあらゆるWebサイトからのリクエストを許可することになります。公開APIや誰でもアクセスできるリソースであれば問題ありませんが、ユーザー認証が必要なAPIや機密情報を含むAPIでは、予期せぬサイトからの悪意あるリクエストを許してしまうリスクがあります。

特にcredentials(CookieやHTTP認証情報)を伴うリクエストでは、Access-Control-Allow-Origin: *は使用できません。この場合、必ず許可するオリジンを具体的に指定する必要があります。セキュリティを考慮するなら、許可するオリジンを限定することが鉄則です。

Webデザインコース

まとめ

fetchでCORSエラーに遭遇したときは、まず落ち着いて「なぜブラウザが通信をブロックしているのか?」という根本原因に立ち返ることが重要です。CORSはWebのセキュリティを保つための重要な仕組みであり、その制限を理解することが、適切な解決策を見つける第一歩となります。 今回の記事で解説したように、ほとんどのCORSエラーは、以下のいずれかの方法で解決できます。

CORSエラー解決方法

  • サーバー側の設定を見直す
    これが最も根本的で正しい解決策です。バックエンドエンジニアに、Access-Control-Allow-Originヘッダーを正しく設定してもらいましょう。
  • ローカル開発環境でプロキシを利用する
    開発中の限られた時間であれば、package.jsonや開発ツールの設定でプロキシを有効にするのが最も手軽な回避策です。
  • リクエストの内容を確認する
    複雑なリクエストの場合は、fetchのオプション(modecredentials)が正しく設定されているかを確認します。

単にエラーを回避するだけでなく、CORSの仕組みを理解することは、フロントエンドとバックエンドの連携をスムーズにし、より安全なWebアプリケーションを構築するために不可欠なスキルです。今日学んだ知識を活かして、今後の開発に役立ててください。

まずは無料体験・説明会に参加を♪【Winスクール】
タイトルとURLをコピーしました