| この記事の要点 |
|
エラーの全文例
Access to XMLHttpRequest at 'https://api.example.com/users'
from origin 'http://localhost:3000' has been blocked by CORS policy:
No 'Access-Control-Allow-Origin' header is present on the requested resource.
# preflight が失敗するケース
Access to fetch at 'https://api.example.com/users' from origin 'http://localhost:3000'
has been blocked by CORS policy: Response to preflight request doesn't pass
access control check: It does not have HTTP ok status.
# credentials 付きのケース
Access to XMLHttpRequest at 'https://api.example.com/login' from origin
'https://app.example.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'.
CORS の仕組み
ブラウザは Same-Origin Policy により、別オリジンへの XHR / fetch をデフォルトでブロックします。CORS はサーバが「許可する」と明示することでこれを緩和する仕組みです。
| 項目 | 説明 |
|---|---|
| オリジン | scheme + host + port (例: https://example.com:443) |
| Same-Origin | scheme / host / port がすべて一致 |
| Cross-Origin | 1 つでも違えば別オリジン |
| Simple Request | GET / HEAD / POST かつ Content-Type 限定。preflight 不要 |
| Preflight Request | PUT / DELETE / PATCH / JSON POST 等で OPTIONS が事前送信される |
| Credentials | cookie / Authorization ヘッダを含めるか |
必要な CORS レスポンスヘッダ
| ヘッダ | 用途 | 例 |
|---|---|---|
Access-Control-Allow-Origin | 許可するオリジン | https://app.example.com または * |
Access-Control-Allow-Methods | 許可する HTTP メソッド | GET, POST, PUT, DELETE, OPTIONS |
Access-Control-Allow-Headers | 許可するリクエストヘッダ | Content-Type, Authorization, X-Requested-With |
Access-Control-Allow-Credentials | cookie 送信許可 | true |
Access-Control-Max-Age | preflight キャッシュ秒数 | 86400 |
Access-Control-Expose-Headers | JS から読み取り可能ヘッダ | X-Total-Count |
対処1: Laravel
Laravel 7+ は fruitcake/laravel-cors 同梱で config/cors.php 編集だけで OK:
// config/cors.php
return [
'paths' => ['api/*', 'sanctum/csrf-cookie', 'login', 'logout'],
'allowed_methods' => ['*'],
'allowed_origins' => [
'http://localhost:3000',
'http://localhost:5173',
'https://app.example.com',
],
'allowed_origins_patterns' => [],
'allowed_headers' => ['*'],
'exposed_headers' => [],
'max_age' => 0,
'supports_credentials' => true, // ★ Sanctum 利用時は true
];
// 設定キャッシュをクリア
// php artisan config:clear
対処2: Spring Boot (Java)
// コントローラに付与
@RestController
@CrossOrigin(origins = "https://app.example.com",
methods = {RequestMethod.GET, RequestMethod.POST},
allowCredentials = "true")
public class UserController {
@GetMapping("/users")
public List<User> list() { ... }
}
// グローバル設定
@Configuration
public class CorsConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/api/**")
.allowedOrigins("https://app.example.com",
"http://localhost:5173")
.allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
.allowedHeaders("*")
.allowCredentials(true)
.maxAge(3600);
}
}
対処3: Express (Node.js)
const express = require('express');
const cors = require('cors');
const app = express();
// 簡易: 全許可 (開発用)
app.use(cors());
// 本番: 明示許可
app.use(cors({
origin: ['https://app.example.com', 'http://localhost:5173'],
credentials: true,
methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'],
allowedHeaders: ['Content-Type', 'Authorization', 'X-Requested-With'],
maxAge: 86400,
}));
// ルート単位
app.get('/users', cors(), (req, res) => { ... });
対処4: Nginx でヘッダ追加
server {
listen 443 ssl;
server_name api.example.com;
location / {
# preflight (OPTIONS) 応答
if ($request_method = 'OPTIONS') {
add_header 'Access-Control-Allow-Origin' 'https://app.example.com';
add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, OPTIONS';
add_header 'Access-Control-Allow-Headers' 'Content-Type, Authorization';
add_header 'Access-Control-Allow-Credentials' 'true';
add_header 'Access-Control-Max-Age' 86400;
return 204;
}
# 通常リクエスト応答
add_header 'Access-Control-Allow-Origin' 'https://app.example.com' always;
add_header 'Access-Control-Allow-Credentials' 'true' always;
proxy_pass http://backend;
}
}
対処5: 開発時はプロキシで回避
本番と同じ CORS 設定を毎回書くのが面倒な場合、開発サーバのプロキシ機能を使うとブラウザから見て同一オリジンになります:
// vite.config.js
export default defineConfig({
server: {
proxy: {
'/api': {
target: 'http://localhost:8000', // Laravel など
changeOrigin: true,
rewrite: (path) => path.replace(/^\/api/, '/api'),
},
},
},
});
// Vue 側からは /api/users と書けば
// 実際は http://localhost:8000/api/users へプロキシ
// ブラウザ目線では同一オリジンなので CORS 不要// webpack-dev-server (Vue CLI / Nuxt 2)
module.exports = {
devServer: {
proxy: {
'/api': {
target: 'http://localhost:8000',
changeOrigin: true,
},
},
},
};
// Next.js next.config.js
module.exports = {
async rewrites() {
return [{ source: '/api/:path*', destination: 'http://localhost:8000/api/:path*' }];
},
};
credentials: include 利用時の注意
cookie や Authorization ヘッダを送る場合、サーバは credentials を許可し、Origin を 具体値 (* 不可) で返す必要があります:
// クライアント (axios)
const api = axios.create({
baseURL: 'https://api.example.com',
withCredentials: true, // ★ cookie 送る
});
// サーバ
// Access-Control-Allow-Origin: https://app.example.com ★ * は不可
// Access-Control-Allow-Credentials: true ★ 必須
preflight (OPTIONS) でつまずくパターン
- POST +
Content-Type: application/json→ preflight 発火 Authorizationヘッダ付き → preflight 発火- カスタムヘッダ (
X-Custom-*) → preflight 発火 - サーバが OPTIONS を 404 / 405 で返すと CORS エラー
- Nginx で
OPTIONSをバックエンドに転送し忘れる
FAQ
Q: Access-Control-Allow-Origin: * でいいのでは?
A: 開発や公開 API は OK。ただし credentials: true とは併用できない。本番は具体値を指定。
Q: フロントエンドの修正で CORS を直せる?
A: 不可能。CORS はサーバが許可する仕組み。開発時はプロキシで回避。
Q: Postman では成功するのにブラウザでは失敗する
A: Postman は CORS を無視する。ブラウザだけが Same-Origin Policy を強制。サーバ側の設定が原因。
子ページ
子ページはありません
同階層のページ
- Uncaught TypeError: Illegal invocation
- Form submission canceled because the form is not connected
- Uncaught TypeError: location.href is not a function
- Access to XMLHttpRequest at 'url1' from origin 'url2' has been blocked
- Uncaught TypeError: Cannot read properties of null (reading 'addEventListener')
人気ページ
- 1 Eclipseで「サーバーに追加または除去できるリソースがありません。」の原因と対処法
- 2 tomcat の起動 / 停止ログと catalina.log・catalina.out の違い
- 3 JavaScript で base URL を取得する方法|window.location.origin
- 4 YouTube Data API v3 エラー一覧|403・400・404 の原因と対処
- 5 Laravel エラー一覧|500/Blade/DB 接続/ルーティングの代表エラー
- 6 3Dグラフィックスとは|モデリング/レンダリング/主要ソフトウェア (Blender / Maya)
- 7 Spring Frameworkのアノテーション一覧
- 8 【Spring】@Valueアノテーションとは
- 9 CATALINA_HOME の確認方法 (Linux / Mac)
- 10 【Spring】@Autowiredアノテーションとは
最近更新/作成されたページ
- プロジェクトをTomcatプロジェクトとして認識させる方法 2026-10-07 22:32:50
- MySQLの1366 Incorrect string value|Laravelの文字コード・絵文字エラー 2026-10-07 21:54:03
- curlの証明書ホスト名不一致|旧エラー51・現行60の確認と対処 2026-10-07 21:54:03
- LaravelのMassAssignmentException|fillableの原因と安全な対処 2026-10-07 21:54:03
- Eclipse で Tomcat の起動ログがコンソールに出ない時の確認手順 2026-10-07 21:54:02
- MySQLにおける中央値(Median)の導き方(バージョン8未満) 2026-10-07 13:49:45
- getInputForward 2026-10-07 13:41:15
- JSONから配列に変換 2026-10-07 13:41:15
- ビューから値をモデルに格納しコントローラーで受け取る方法 2026-10-07 13:23:41
- Laravelのテーブル作成と定義変更|マイグレーション・up/down・注意点 2026-10-07 13:23:41
- NumPy 配列に要素を追加する方法 (append / concatenate) 2026-10-07 13:23:41
- MariaDB・MySQLで現在日時を取得する方法|NOW・タイムゾーン・保存型 2026-10-07 13:13:36
- 【django】テンプレートで定数を使用する方法 2026-10-07 13:10:15
- Spring BootにおけるApplication.propertiesの環境依存設定の分割方法 2026-10-07 12:09:35
- Not supported for DML operations【Springエラー】 2026-10-07 11:09:38