
- はじめに
- CORSとは
- オリジンとは
- なぜCORSが必要なのか
- CORSエラーが発生する例
- Access-Control-Allow-Originとは
- Preflight Requestとは
- CORSエラーの主な原因
- 許可されているOriginが異なる
- HTTPメソッドが許可されていない
- HTTPヘッダーが許可されていない
- CORSエラーの対応方法
- 対応方法1:APIサーバー側でCORSを許可する
- LaravelでCORSを設定する場合
- Node.js / ExpressでCORSを設定する場合
- 対応方法2:バックエンドを経由してAPIへアクセスする
- 対応方法3:開発サーバーのProxyを利用する
- mode: ‘no-cors’では基本的に解決しない
- Chromeのセキュリティ設定を無効化する方法はおすすめしない
- axiosに変更してもCORSエラーは解決しない
- Postmanでは成功するのにブラウザでは失敗する理由
- CORSエラーが発生したときの確認ポイント
- まとめ
はじめに
ReactやVue.js、React Nativeなどを利用してフロントエンドの開発を行っていると、外部APIからデータを取得する場面があります。
例えば、JavaScriptからfetchやaxiosを利用して外部サービスのREST APIへアクセスした際、次のようなエラーが表示されることがあります。
Access to fetch at 'https://example.com/api'
from origin 'http://localhost:3000'
has been blocked by CORS policy
また、次のようなエラーが表示される場合もあります。
Response to preflight request doesn't pass access control check:
No 'Access-Control-Allow-Origin' header is present
on the requested resource.
これは**CORS(Cross-Origin Resource Sharing)**に関するエラーです。
今回は、CORSとはどのような仕組みなのか、なぜCORSエラーが発生するのか、そしてフロントエンド開発でどのように対応すればよいのかを解説します。
CORSとは
CORSとは、
Cross-Origin Resource Sharing
の略称で、日本語では「オリジン間リソース共有」と呼ばれます。
簡単に説明すると、
異なるWebサイトやドメイン間でデータをやり取りする際のアクセス制御の仕組み
です。
Webブラウザには、セキュリティ対策として「Same-Origin Policy(同一オリジンポリシー)」という仕組みがあります。
基本的には、JavaScriptから異なるオリジンのサーバーへ自由にアクセスすることはできません。
例えば、次のWebアプリがあるとします。
http://localhost:3000
ここから、次の外部APIへアクセスします。
https://api.example.com/users
この場合、
localhost:3000
と、
api.example.com
は異なるオリジンになります。
そのため、APIサーバー側がアクセスを許可していなければ、ブラウザによって通信が制限されます。
オリジンとは
CORSを理解するうえで重要なのが「オリジン」です。
オリジンは基本的に、次の3つの組み合わせによって決まります。
- プロトコル
- ホスト名
- ポート番号
例えば、
https://example.com:443
であれば、
プロトコル:https
ホスト名:example.com
ポート番号:443
となります。
どれか1つでも異なれば、基本的には異なるオリジンとして扱われます。
例えば、
http://example.com
と、
https://example.com
はHTTPとHTTPSが異なるため別オリジンです。
また、
http://localhost:3000
と、
http://localhost:5173
についても、ポート番号が異なるため別オリジンとして扱われます。
なぜCORSが必要なのか
もしCORSのような制限がなければ、悪意のあるWebサイトから別のWebサービスへ勝手に通信できてしまう可能性があります。
例えば、ユーザーがあるWebサービスへログインした状態で、悪意のあるサイトを開いたとします。
そのサイトのJavaScriptから自由に別サービスへアクセスできてしまうと、ユーザーが意図しない操作やデータ取得が行われる可能性があります。
そのためブラウザでは、異なるオリジン間の通信を制限しています。
CORSは単なるエラーではなく、Webブラウザの重要なセキュリティ機能の一つです。
CORSエラーが発生する例
例えばReactから、次のように外部APIへアクセスしたとします。
fetch('https://api.example.com/users')
.then(response => response.json())
.then(data => {
console.log(data);
});
APIサーバーがCORSを許可していない場合、ブラウザ側では次のようなエラーが発生することがあります。
Access to fetch at 'https://api.example.com/users'
from origin 'http://localhost:3000'
has been blocked by CORS policy
重要なのは、
fetchの書き方が間違っているとは限らない
という点です。
CORSエラーの場合、原因はAPIサーバー側の設定であることが少なくありません。
Access-Control-Allow-Originとは
CORSでは、APIサーバーがレスポンスヘッダーを利用してアクセス可能なオリジンを指定します。
代表的なものが、
Access-Control-Allow-Origin
です。
例えばAPIサーバーから、
Access-Control-Allow-Origin: https://example.com
というレスポンスヘッダーが返ってきた場合、
https://example.com
からのアクセスを許可する、という意味になります。
すべてのオリジンを許可する場合には、
Access-Control-Allow-Origin: *
と設定することもあります。
ただし、本番環境ではセキュリティ上の理由から、必要なドメインだけを許可するのが一般的です。
Preflight Requestとは
CORSエラーを調査していると、
preflight request
という言葉を見ることがあります。
Preflight Request(プリフライトリクエスト)とは、本来のAPI通信を行う前に、
「この通信を実行してもよいですか?」
とブラウザがAPIサーバーへ確認する通信です。
通常、
OPTIONS
というHTTPメソッドが利用されます。
例えばフロントエンド側で、
fetch('https://api.example.com/users', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer TOKEN'
},
body: JSON.stringify({
name: 'Taro'
})
});
のような通信を行った場合、先にOPTIONSリクエストが送信されることがあります。
イメージとしては、
ブラウザ
↓
OPTIONS /users
↓
APIサーバー
↓
アクセス許可を返す
↓
POST /users
という流れです。
APIサーバーがOPTIONSリクエストへ正しく応答しない場合、
Response to preflight request doesn't pass access control check
というエラーが発生する場合があります。
CORSエラーの主な原因
CORSエラーには、いくつか代表的な原因があります。
APIサーバーがCORSを許可していない
最も代表的なケースです。
APIサーバーから、
Access-Control-Allow-Origin
が返されていない場合、ブラウザによってブロックされることがあります。
許可されているOriginが異なる
例えばサーバー側で、
Access-Control-Allow-Origin: https://example.com
だけを許可しているにもかかわらず、
http://localhost:3000
からアクセスするとCORSエラーになります。
開発環境の場合、
http://localhost:3000

http://localhost:5173
なども許可する必要があります。
HTTPメソッドが許可されていない
例えば、
GET
のみ許可されているAPIへ、
POST
PUT
DELETE
などを送信するとCORSエラーになる場合があります。
サーバー側では、
Access-Control-Allow-Methods
によって許可するHTTPメソッドを設定します。
例:
Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS
HTTPヘッダーが許可されていない
APIトークンやAuthorizationヘッダーなど、独自のヘッダーを送信する場合にも注意が必要です。
例えば、
headers: {
Authorization: 'Bearer TOKEN'
}
を送信する場合、APIサーバー側でそのヘッダーが許可されている必要があります。
サーバー側では、
Access-Control-Allow-Headers
を設定します。
例:
Access-Control-Allow-Headers: Content-Type, Authorization
CORSエラーの対応方法
CORSエラーが発生した場合、基本的にはAPIサーバー側で対応する必要があります。
フロントエンド側のJavaScriptだけでCORS制限を解除することはできません。
ここはCORSを理解するうえで非常に重要なポイントです。
対応方法1:APIサーバー側でCORSを許可する
自分で管理しているAPIの場合、サーバー側のCORS設定を変更します。
例えばレスポンスヘッダーとして、
Access-Control-Allow-Origin: https://example.com
を返します。
開発環境であれば、
Access-Control-Allow-Origin: http://localhost:3000
などを設定します。
LaravelでCORSを設定する場合
LaravelでAPIを開発している場合には、CORS設定を利用できます。
Laravelのバージョンによって設定方法は異なりますが、CORS設定では主に次のような項目を指定します。
'allowed_methods' => ['*'],
'allowed_origins' => [
'http://localhost:3000',
'https://example.com',
],
'allowed_headers' => ['*'],
本番環境では、
'allowed_origins' => ['*']
としてすべて許可するよりも、
'allowed_origins' => [
'https://example.com',
]
のように、アクセスを許可するフロントエンドのドメインを指定した方が安全です。
Node.js / ExpressでCORSを設定する場合
Node.jsとExpressでAPIを作成している場合には、corsパッケージを利用できます。
インストールします。
npm install cors
次にExpressへ設定します。
const express = require('express');
const cors = require('cors');
const app = express();
app.use(cors({
origin: 'http://localhost:3000'
}));
app.get('/api/users', (req, res) => {
res.json([
{
id: 1,
name: 'Taro'
}
]);
});
app.listen(3001);
複数のオリジンを許可したい場合は、環境に応じた設定を行います。
対応方法2:バックエンドを経由してAPIへアクセスする
外部サービスのAPIを利用している場合、自分でAPI側のCORS設定を変更できないことがあります。
例えば、
React
↓
外部API
という構成ではCORSエラーになる場合があります。
この場合には、
React
↓
自社バックエンド
↓
外部API
という構成に変更します。
例えばLaravelを利用している場合、
React
↓
Laravel
↓
外部API
とします。
Laravel側から外部APIへアクセスします。
use Illuminate\Support\Facades\Http;
$response = Http::get('https://api.example.com/users');
return response()->json($response->json());
ReactからはLaravelのAPIへアクセスします。
const response = await fetch('/api/users');
const data = await response.json();
console.log(data);
この方法には、
- CORS問題を回避しやすい
- APIキーをフロントエンドへ公開しなくてよい
- APIアクセス処理をバックエンド側へ集約できる
というメリットがあります。
特にAPIトークンやAPIキーを利用するサービスの場合には、バックエンド経由にする方法が適しています。
対応方法3:開発サーバーのProxyを利用する
ローカル開発環境では、ViteなどのProxy機能を利用する方法もあります。
例えばViteであれば、vite.config.jsへ次のように設定できます。
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
export default defineConfig({
plugins: [react()],
server: {
proxy: {
'/api': {
target: 'https://api.example.com',
changeOrigin: true,
secure: true,
},
},
},
});
React側では、
fetch('/api/users');
のようにアクセスします。
開発サーバーが、
/api
へのアクセスを、
https://api.example.com
へ中継します。
ただし、この方法は主に開発環境向けの対応方法です。
本番環境では、WebサーバーやバックエンドAPIなどを含めた構成を検討する必要があります。
mode: ‘no-cors’では基本的に解決しない
CORSエラーについて調べると、
fetch(url, {
mode: 'no-cors'
});
という方法を見かけることがあります。
しかし、
mode: 'no-cors'
は一般的なREST APIからJSONデータを取得したい場合の解決策にはなりません。
レスポンスがopaqueとなり、JavaScriptからレスポンス本文を通常通り読み取れなくなるためです。
そのため、
mode: 'no-cors'
を追加すればCORSエラーを解決できる、とは考えない方がよいでしょう。
Chromeのセキュリティ設定を無効化する方法はおすすめしない
開発時にブラウザのセキュリティを無効化してCORSを回避する方法もインターネット上では紹介されています。
しかし、これはCORSの根本的な解決にはなりません。
自分のブラウザで動作したとしても、通常の環境でアクセスしたユーザーにはCORSエラーが発生します。
そのため、
APIサーバー側のCORS設定を修正する
または、
バックエンドサーバーを経由する
という方法を基本的な対応方針とすることをおすすめします。
axiosに変更してもCORSエラーは解決しない
例えばfetchでCORSエラーが発生したため、axiosへ変更するケースがあります。
axios.get('https://api.example.com/users');
しかし、
fetch → axios
へ変更しただけではCORSエラーは基本的に解決しません。
CORSはブラウザのセキュリティ機能であり、JavaScriptのHTTP通信ライブラリによって発生している問題ではないためです。
そのため、
fetchでCORSエラー
が発生している場合、
axiosならアクセスできる
とは限りません。
Postmanでは成功するのにブラウザでは失敗する理由
CORSを調査するときによくあるのが、
PostmanではAPIアクセスできる
ブラウザからはCORSエラーになる
というケースです。
これは異常ではありません。
CORSは主にWebブラウザが適用するセキュリティ制限だからです。
そのため、
curl
Postman
PHP
Laravel
Node.js
などからAPIへアクセスすると成功するにもかかわらず、
React
Vue.js
ブラウザ上のJavaScript
からアクセスするとCORSエラーになることがあります。
この場合、
API自体にアクセスできないのではなく、ブラウザからのクロスオリジン通信が許可されていない
可能性があります。
CORSエラーが発生したときの確認ポイント
CORSエラーが発生した場合には、次の項目を確認すると原因を特定しやすくなります。
- フロントエンドとAPIのOriginが異なっていないか
- APIから
Access-Control-Allow-Originが返されているか - 自分のフロントエンドのOriginが許可されているか
OPTIONSリクエストが成功しているか- HTTPメソッドが許可されているか
- AuthorizationなどのHTTPヘッダーが許可されているか
- API側のCORS設定を変更できるサービスなのか
- バックエンド経由にする必要がないか
Chromeなどのブラウザでは、開発者ツールの「Network」タブから通信内容を確認できます。
特に、
OPTIONS
リクエストのStatus CodeやResponse Headersを確認すると、CORSエラーの原因を特定しやすくなります。
まとめ
CORSは、
異なるオリジン間でWebリソースへアクセスする際のセキュリティ制御
です。
ReactやVue.jsなどのフロントエンドから外部APIを利用していると、
blocked by CORS policy
や、
No 'Access-Control-Allow-Origin' header
などのエラーが発生することがあります。
この場合、単純にfetchやaxiosのコードを変更するのではなく、まずAPIサーバー側のCORS設定を確認することが重要です。
自分で管理しているAPIであれば、
Access-Control-Allow-Origin
Access-Control-Allow-Methods
Access-Control-Allow-Headers
などを適切に設定します。
一方、外部サービスのAPIなど、自分でCORS設定を変更できない場合には、
フロントエンド
↓
自社バックエンド
↓
外部API
という構成にして、LaravelやNode.jsなどのバックエンドを経由してアクセスする方法も有効です。
特にAPIキーやAPIトークンを利用するサービスでは、認証情報をフロントエンドへ直接記述しないという意味でも、バックエンド経由でアクセスする設計がおすすめです。
CORSエラーが発生した場合には、エラー文だけを見るのではなく、ブラウザの開発者ツールからOPTIONSリクエストやレスポンスヘッダーを確認し、どの段階で通信が拒否されているのかを確認してみましょう。

