Node.jsアプリケーションのCORSエラー解決法:5分で実装できる完全ガイド

CORSエラーとは?開発者が直面する一般的な問題
フロントエンドアプリケーションから異なるドメインのAPIにリクエストを送ると、ブラウザのコンソールに次のようなエラーが表示されることがあります。
Access to fetch at 'https://api.example.com/data' from origin 'https://myapp.com'
has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present
on the requested resource.
これが「Cross-Origin Resource Sharing (CORS)」エラーです。ブラウザのセキュリティ機能によって、異なるオリジン(ドメイン、ポート、プロトコル)間でのリソース共有が制限されています。
CORSエラーが発生する主な状況は以下のとおりです:
- ローカル開発環境(
localhost:3000
)からAPIサーバー(localhost:8000
)へのリクエスト - フロントエンドとバックエンドが異なるドメインで稼働している場合
- 開発環境と本番環境での設定の違いによるエラー
このエラーは単なる設定の問題であり、適切なヘッダーを設定することで簡単に解決できます。Node.jsとExpress.jsを使う場合、正しいCORS設定を実装して、フロントエンドからのリクエストを許可する方法を見ていきましょう。
Express.jsでCORS対応を実装する方法
Express.jsでCORS対応を実装する最も簡単な方法は、cors
ミドルウェアを使用することです。以下の手順で簡単に実装できます。
1. cors ミドルウェアのインストール
npm install cors
# または
yarn add cors
2. ミドルウェアの設定
const express = require('express');
const cors = require('cors');
const app = express();
// すべてのルートで CORS を有効にする
app.use(cors());
// APIルートの設定
app.get('/api/data', (req, res) => {
res.json({ message: 'This is your data!' });
});
app.listen(8000, () => {
console.log('Server running on http://localhost:8000');
});
これだけで、あらゆるオリジンからのリクエストを許可する基本的なCORS設定が完了します。ブラウザはレスポンスに含まれる以下のようなヘッダーを確認します:
Access-Control-Allow-Origin: *
この設定はシンプルですが、本番環境ではセキュリティ上の理由から、より制限的な設定が推奨されます。次のセクションでは、より詳細なカスタマイズ方法を見ていきましょう。
特定のオリジンやヘッダーに対するCORS設定のカスタマイズ
実際の開発では、特定のオリジンからのリクエストのみを許可したり、特定のHTTPヘッダーやメソッドを許可したりする必要があります。corsミドルウェアではこれらの設定を簡単にカスタマイズできます。
特定のオリジンのみを許可する
const corsOptions = {
origin: 'https://myapp.com', // 特定のドメインのみ許可
optionsSuccessStatus: 200 // レガシーブラウザ対応
};
app.use(cors(corsOptions));
複数のオリジンを許可する
const corsOptions = {
origin: ['https://myapp.com', 'https://admin.myapp.com'],
optionsSuccessStatus: 200
};
app.use(cors(corsOptions));
関数を使用して動的に判断する
const corsOptions = {
origin: function (origin, callback) {
// ホワイトリストの定義
const whitelist = ['https://myapp.com', 'https://admin.myapp.com'];
// 開発環境では undefined になることがあるため許可
if (!origin || whitelist.indexOf(origin) !== -1) {
callback(null, true);
} else {
callback(new Error('CORS policy violation'));
}
},
optionsSuccessStatus: 200
};
app.use(cors(corsOptions));
その他のカスタマイズオプション
const corsOptions = {
origin: 'https://myapp.com',
methods: ['GET', 'POST', 'PUT', 'DELETE'], // 許可するHTTPメソッド
allowedHeaders: ['Content-Type', 'Authorization'], // 許可するHTTPヘッダー
exposedHeaders: ['Content-Range', 'X-Total-Count'], // クライアントに公開するヘッダー
credentials: true, // Cookieを含めたリクエストを許可
maxAge: 86400 // プリフライトリクエストの結果をキャッシュする時間(秒)
};
app.use(cors(corsOptions));
これらの設定を使用して、アプリケーションのセキュリティ要件に合わせたCORS設定を実装できます。
フロントエンドからのプリフライトリクエストを処理する
ブラウザは、特定の「複雑な」リクエストを送信する前に、サーバーがそのリクエストを受け入れるかどうかを確認するために「プリフライトリクエスト」を送信します。これは OPTIONS
メソッドを使用して行われます。
プリフライトリクエストが発生する主な条件は以下のとおりです:
PUT
、DELETE
、CONNECT
、OPTIONS
、TRACE
、PATCH
メソッドを使用する場合- Content-Type が
application/json
などの単純でないタイプの場合 - カスタムヘッダーを含む場合(例:
X-API-Key
)
プリフライトリクエストへの対応
corsミドルウェアは通常、プリフライトリクエストを自動的に処理しますが、より細かい制御が必要な場合は以下のように実装できます:
// OPTIONS リクエストに対する特別な処理
app.options('/api/data', cors(corsOptions)); // プリフライト用の特定ルート
// 実際のAPIエンドポイント
app.put('/api/data', cors(corsOptions), (req, res) => {
// リソースを更新するコード
res.json({ success: true });
});
プリフライトリクエストの例
ブラウザからのプリフライトリクエストは次のようになります:
OPTIONS /api/data HTTP/1.1
Host: api.example.com
Origin: https://myapp.com
Access-Control-Request-Method: PUT
Access-Control-Request-Headers: Content-Type, Authorization
サーバーからの適切なレスポンスは:
HTTP/1.1 200 OK
Access-Control-Allow-Origin: https://myapp.com
Access-Control-Allow-Methods: GET, POST, PUT, DELETE
Access-Control-Allow-Headers: Content-Type, Authorization
Access-Control-Max-Age: 86400
このレスポンスにより、ブラウザは実際のPUTリクエストを送信することが許可されます。Access-Control-Max-Age
ヘッダーは、ブラウザがこのプリフライトレスポンスをキャッシュする時間(秒)を指定します。
開発環境と本番環境でのCORS設定の違い
開発環境と本番環境では、異なるCORS設定が必要になることがよくあります。これらの環境間で設定を切り替える方法を見ていきましょう。
環境変数を使用した設定
Node.jsでは、環境変数を使用して異なる環境での設定を管理するのが一般的です。
// .env.development と .env.production に環境変数を定義
// app.js
const express = require('express');
const cors = require('cors');
const app = express();
// 環境に応じてCORS設定を変更
const corsOptions = {
origin: process.env.NODE_ENV === 'production'
? process.env.ALLOWED_ORIGIN // 例: 'https://myapp.com'
: '*', // 開発環境ではすべてのオリジンを許可
credentials: true
};
app.use(cors(corsOptions));
複数の環境に対応する動的な設定
const express = require('express');
const cors = require('cors');
const app = express();
// 環境に応じたオリジンリストの設定
const whitelist = {
development: ['http://localhost:3000', 'http://localhost:8080'],
test: ['http://test.myapp.com'],
production: ['https://myapp.com', 'https://admin.myapp.com']
};
const corsOptions = {
origin: function (origin, callback) {
const env = process.env.NODE_ENV || 'development';
const allowedOrigins = whitelist[env];
// 許可されたオリジンリストにあるか、
// 開発環境でのnull origin(例:Postmanからのリクエスト)を許可
if (!origin || allowedOrigins.indexOf(origin) !== -1) {
callback(null, true);
} else {
callback(new Error(`CORS policy violation: ${origin} is not allowed`));
}
},
credentials: true
};
app.use(cors(corsOptions));
環境固有のミドルウェア設定
const express = require('express');
const cors = require('cors');
const app = express();
// 本番環境用のCORS設定
const productionCors = cors({
origin: 'https://myapp.com',
credentials: true,
methods: ['GET', 'POST', 'PUT', 'DELETE'],
maxAge: 86400
});
// 開発環境用のCORS設定
const developmentCors = cors({
origin: '*',
credentials: true
});
// 環境に応じたミドルウェアの選択
if (process.env.NODE_ENV === 'production') {
app.use(productionCors);
} else {
app.use(developmentCors);
}
これらの方法を使用して、開発中は柔軟なCORS設定を使用し、本番環境ではより制限的な設定を適用できます。
トラブルシューティング:よくあるCORSエラーとその解決策
CORSエラーはさまざまな形で発生します。ここでは一般的なエラーパターンとその解決策を紹介します。
1. 「No 'Access-Control-Allow-Origin' header is present」エラー
エラーメッセージ:
Access to fetch at 'https://api.example.com/data' from origin 'https://myapp.com'
has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present
on the requested resource.
解決策:
- サーバー側でCORSミドルウェアが正しく設定されているか確認する
- 正しいオリジンが許可リストに含まれているか確認する
// 基本的なCORS設定を実装
app.use(cors({
origin: 'https://myapp.com' // リクエスト元のドメインを指定
}));
2. 「Method not allowed by CORS」エラー
エラーメッセージ:
Access to fetch at 'https://api.example.com/data' from origin 'https://myapp.com'
has been blocked by CORS policy: Method PUT is not allowed by Access-Control-Allow-Methods
in preflight response.
解決策:
- 許可するメソッドをCORS設定に追加する
app.use(cors({
origin: 'https://myapp.com',
methods: ['GET', 'POST', 'PUT', 'DELETE'] // PUTメソッドを追加
}));
3. 「Header not allowed by CORS」エラー
エラーメッセージ:
Access to fetch at 'https://api.example.com/data' from origin 'https://myapp.com'
has been blocked by CORS policy: Request header field x-custom-header is not allowed
by Access-Control-Allow-Headers in preflight response.
解決策:
- 許可するヘッダーをCORS設定に追加する
app.use(cors({
origin: 'https://myapp.com',
allowedHeaders: ['Content-Type', 'Authorization', 'x-custom-header']
}));
4. 「Credentials flag is true, but Access-Control-Allow-Credentials is not 'true'」エラー
エラーメッセージ:
Access to fetch at 'https://api.example.com/data' from origin 'https://myapp.com'
has been blocked by CORS policy: The value of the 'Access-Control-Allow-Credentials'
header in the response is '' which must be 'true' when the request's credentials mode is 'include'.
解決策:
- credentialsオプションを有効にする
// サーバー側
app.use(cors({
origin: 'https://myapp.com',
credentials: true
}));
// クライアント側(フロントエンド)
fetch('https://api.example.com/data', {
credentials: 'include' // クッキーなどの認証情報を含める
});
5. Node.js以外のサーバーを使用している場合
Express.jsを使用していない場合でも、適切なヘッダーを設定することでCORSを有効にできます:
// Node.js(expressなし)の例
const http = require('http');
http.createServer((req, res) => {
// CORSヘッダーを設定
res.setHeader('Access-Control-Allow-Origin', 'https://myapp.com');
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE');
res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization');
res.setHeader('Access-Control-Allow-Credentials', 'true');
// プリフライトリクエスト(OPTIONS)の処理
if (req.method === 'OPTIONS') {
res.writeHead(204); // No Content
res.end();
return;
}
// 実際のリクエスト処理
res.writeHead(200, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({ message: 'This is your data!' }));
}).listen(8000);
6. プロキシを使用する方法
フロントエンド開発で一時的にCORSエラーを回避するには、開発サーバーのプロキシ機能を使用する方法もあります:
Viteの例:
// vite.config.js
export default {
server: {
proxy: {
'/api': {
target: 'http://localhost:8000',
changeOrigin: true
}
}
}
};
Create React Appの例:
// package.json
{
"proxy": "http://localhost:8000"
}
最終的には本番環境では適切なCORS設定を実装する必要がありますが、開発環境でのテストには便利な手法です。
CORSの設定は一見複雑に見えますが、基本的な原則を理解し、適切なミドルウェアを使用することで、簡単に解決できる問題です。ブラウザとサーバー間の安全な通信を確保するための重要なセキュリティ機能であることを忘れないようにしましょう。
このトピックはこちらの書籍で勉強するのがおすすめ!
この記事の内容をさらに深く理解したい方におすすめの一冊です。実践的な知識を身につけたい方は、ぜひチェックしてみてください!
おすすめコンテンツ
おすすめJavaScript2025/5/5Node.jsとWebSocketで作る!初心者でも実装できるリアルタイムWebアプリケーション開発チュートリアル
'Webの世界は常に進化しています。かつては「リクエストを送信して応答を待つ」という単方向の通信が一般的でしたが、現代のユーザーはよりダイナミックな体験を求めています。リアルタイムWebアプリケーショ...
続きを読む Next.js2025/5/20SSRアプリケーションでのCookieベース認証トラブル解決法!Next.jsとExpressの連携実装ガイド
Server-Side Renderingアプリケーションでよく遭遇するCookieベース認証の問題を解決します。Next.jsとExpressを使った実装例とトラブルシューティング手順を詳しく解説。...
続きを読む Docker2025/5/20Dockerコンテナ内Node.jsアプリの環境変数トラブル解決法
Dockerコンテナ内でNode.jsアプリケーションを実行すると、環境変数が正しく読み込まれない問題に遭遇することがあります。この記事では、具体的な原因と解決策を実用的なコード例で解説します。
続きを読む クラウドネイティブ2025/5/15クラウドネイティブアプリケーション開発完全ガイド:2025年最新のベストプラクティス
モダンなクラウドネイティブアプリケーション開発の全てを解説。マイクロサービス、コンテナ、CI/CD、オブザーバビリティの実装方法と、スケーラブルで堅牢なアプリケーションを構築するためのベストプラクティ...
続きを読む Docker2025/5/20Dockerコンテナ内Node.jsアプリのソースマップデバッグが効かない問題の解決法
Dockerコンテナ内でTypeScriptやBabelでトランスパイルされたNode.jsアプリケーションをデバッグする際、ソースマップが正しく機能せず元のコードでデバッグできない問題の具体的な解決...
続きを読む React2025/5/1Next.jsとTypeScriptで作る高速SSGブログ:初心者でも簡単に実装できる完全ガイド
Next.jsとTypeScriptを組み合わせたSSGブログの作り方を解説します。静的サイト生成の利点から実装方法、デプロイまで、初心者でも理解できるようステップバイステップで説明。コードサンプル付...
続きを読む JavaScript2025/5/14WebSocketを活用したリアルタイムチャットアプリケーション開発ガイド
WebSocketを使って初心者でも作れるリアルタイムチャットアプリケーションの開発方法を解説します。基本概念から実装、デプロイまでステップバイステップで紹介します。
続きを読むGo
2025/5/2Golangの並行処理パターン:効率的なアプリケーション開発のための実践ガイド
Golangのgoroutineとチャネルを使った並行処理パターンを実践的なコード例とともに解説。基本から応用まで、効率的な非同期処理の実装方法とよくあるエラーの回避策を紹介します。
続きを読む