- Angular
Angular proxy.conf.jsonの書き方|開発中のCORSを回避
ng serve の開発サーバーに「/api で始まるリクエストは API サーバーへ転送する」と設定すると、ブラウザから見て画面と API が同じオリジン(http://localhost:4200)になり、開発中の CORS エラーが出なくなります。 設定は、プロキシの設定ファイルを作り、angular.json の serve の options.proxyConfig で指定します。
// src/proxy.conf.json
{
"/api/**": {
"target": "http://localhost:3000",
"secure": false,
"changeOrigin": true
}
}
// angular.json(projects.<名前>.architect の中)
"serve": {
"builder": "@angular/build:dev-server",
"options": {
"proxyConfig": "src/proxy.conf.json"
},
"configurations": { … },
"defaultConfiguration": "development"
}
// コードでは「ホスト名を書かない」相対 URL で呼ぶ
this.http.get('/api/users'); // ○ プロキシを通る
// this.http.get('http://localhost:3000/api/users'); // ✕ プロキシを通らず CORS エラー
同じ画面から、API サーバー(CORS のヘッダーを返さない Node のサーバー)を2通りに呼んだ結果です。
| 呼び方 | 結果 |
|---|---|
http://localhost:3000/api/users(直接) |
blocked by CORS policy。HttpClient は status=0 |
/api/users(プロキシ経由) |
成功:{"server":"users","path":"/api/users"} |
確認環境:Angular 22.2.2(@angular/cli・@angular/build の dev-server。中で Vite 8.3.4 が動く)、Node.js 24.21.0(Linux)。Node で作った小さな API サーバー(ポート 3000・3001・3443)を立て、ng serve の画面を Chromium(Playwright 1.56.1)で開いて、上の結果とこの記事のエラー文・ログを得ました。本番の構成は nginx で同じ形を動かしました。各オプションの意味は angular.dev・Vite のドキュメントと、@angular/build の配布コードで確かめました(確認日 2026年10月12日)。
本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。
(記載例)出典:株式会社RJC「Angular proxy.conf.jsonの書き方|開発中のCORSを回避」
なぜプロキシで CORS エラーが消えるのか
CORS(Cross-Origin Resource Sharing)は、ブラウザが「画面と違うオリジン(スキーム・ホスト・ポートの組)への通信の結果を、そのサーバーが許可していなければ JavaScript に渡さない」しくみです。localhost:4200 の画面から localhost:3000 を呼ぶと、ポートが違うので別オリジンになります。
直接呼んだときに、Chromium のコンソールに出たエラーです。
Access to fetch at 'http://localhost:3000/api/users' from origin 'http://localhost:4200' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
POST で JSON を送ると、本番の前に OPTIONS の確認(プリフライト)が飛び、そこで止まりました。
Access to fetch at 'http://localhost:3000/api/users' from origin 'http://localhost:4200' 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.
API サーバーのログを見ると、GET はサーバーまで届いていて、ブラウザが結果を捨てていたことが分かります。POST は OPTIONS だけが届き、POST 本体は送られませんでした。
[users:3000] GET /api/users host=localhost:3000 origin=http://localhost:4200
[users:3000] OPTIONS /api/users host=localhost:3000 origin=http://localhost:4200
プロキシを使うと、通信の流れが次のように変わります。
ブラウザ ──(/api/users)──▶ ng serve(localhost:4200)──▶ API(localhost:3000)
同じオリジン サーバー同士の通信なので CORS は関係しない
ブラウザは localhost:4200 とだけ話すので、CORS の検査が起きません。CORS のしくみとエラー文の読み方は、関連記事「CORSエラーの原因と解決方法|エラーメッセージ別に解説」で扱っています。
設定の手順
1. プロキシの設定ファイルを作る
angular.dev の手順では src/proxy.conf.json に置きます。場所は自由で、angular.json で指定するパスはワークスペースのルート(angular.json のある場所)からの相対パスです。ファイルが無いと、ng serve は次のメッセージで止まる作りでした(@angular/build の配布コードによる)。
Proxy configuration file /…/src/proxy.conf.json does not exist.
2. angular.json で指定する(またはコマンドで渡す)
冒頭のとおり、serve の options に "proxyConfig" を書きます。v22 の ng new が作る angular.json の serve には options が無いので、builder の下に options ごと足します。毎回コマンドで渡す形もあります。
ng serve --proxy-config src/proxy.conf.json
3. HttpClient は相対 URL で呼ぶ
http://localhost:3000/... のように完全な URL を書くと、ブラウザは開発サーバーを通らずに直接 API へ行きます。プロキシを使うときは /api/... と書きます。 環境ごとに API の場所を変える方法は、関連記事「Angular environmentで環境変数を切り替える設定手順」で扱っています。
4. 設定を変えたら ng serve を再起動する
ng serve を動かしたまま設定ファイルの target を書き換えても、転送先は前のままでした(ECONNREFUSED 127.0.0.1:3001 が出続けた)。止めて起動し直すと、新しい転送先に変わりました。angular.dev にも「プロキシ設定の変更を反映するには ng serve の再起動が必要」とあります。
パスの書き方(どのリクエストが転送されるか)
キー("/api/**" の部分)で、転送するリクエストを決めます。angular.dev の説明と、@angular/build の配布コードの動きは次のとおりです。
| キー | 一致するもの | 一致しないもの |
|---|---|---|
/api |
/api・/api/users・/api-docs(前方一致) |
/v1/api |
/api/* |
/api/users |
/api・/api/users/1 |
/api/** |
/api・/api/users・/api/users/1 |
/api-docs |
^/api/(users|items) |
^ で始めると正規表現 |
— |
/api/* の設定で /api/users/1 を呼ぶと、転送されず、開発サーバーが index.html を返しました(200 text/html)。* と ** の違いで、深い階層が転送されないことがあります。 迷ったら /api/** か、前方一致の /api を使います。
@angular/build の配布コードでは、* を含むキーを正規表現に変換してから Vite に渡していました。複数のキーに一致するときは、上に書いたものが先に使われます(配布コードのコメントに「Vite proxies a request with the first entry that matches it」とあります)。
オプション一覧
v22 の開発サーバーは、Vite の server.proxy を使っています。Vite のドキュメントでは、各キーの設定は http-proxy-3 のオプションを広げたものと説明されています。よく使うものは次のとおりです。
| オプション | 意味 | JSON で書けるか |
|---|---|---|
target |
転送先(http://localhost:3000 など) |
○ |
changeOrigin |
Host ヘッダーを転送先のものに書き換える |
○ |
secure |
false で、転送先の自己署名証明書を許す |
○ |
pathRewrite |
パスを置き換える(Angular が rewrite に変換) |
○ |
ws |
WebSocket も転送する | ○ |
headers |
転送時に足すヘッダー | ○ |
rewrite |
パスを置き換える関数(Vite の書き方) | JS のみ |
configure |
プロキシ本体に処理を足す関数(ログなど) | JS のみ |
bypass |
転送せずに返す・別の URL にする関数 | JS のみ |
logLevel |
v22 では何も出なかった(後述) | ○(効かない) |
changeOrigin:Host ヘッダーの書き換え
API サーバーのログで、受け取った Host ヘッダーを比べました。
| 設定 | API が受け取った Host |
|---|---|
"changeOrigin": true |
localhost:3000 |
| 書かない(JSON のオブジェクト形) | localhost:4200 |
文字列だけで書いた("/auth": "http://localhost:3001") |
localhost:3001 |
バーチャルホスト(Host ヘッダーで振り分けるサーバー)や、Host を検査する API へ転送するときは changeOrigin: true にします。値を文字列だけで書くと、Vite は changeOrigin: true として扱いました。
secure:自己署名証明書の HTTPS へ転送する
自己署名証明書の HTTPS サーバー(ポート 3443)へ転送しました。
[vite] http proxy error: /secure-ng/x
Error: self-signed certificate; if the root CA is installed locally, try running Node.js with --use-system-ca
"secure": true(既定の動き)ではこのエラーで 502 になり、"secure": false にすると通りました。社内の検証環境など、証明書を検証できない転送先に使います。
pathRewrite:パスを置き換える
{
"/v1/**": {
"target": "http://localhost:3000",
"pathRewrite": { "^/v1": "/api/v1" }
}
}
/v1/orders を呼ぶと、API には /api/v1/orders で届きました。pathRewrite のキーは正規表現として扱われ、配布コードでは最初に置き換えが起きたものだけが使われます。先頭を消すだけなら { "^/api": "" } です。
複数の API に振り分ける
{
"/api/**": { "target": "http://localhost:3000", "changeOrigin": true },
"/v1/**": { "target": "http://localhost:3000", "pathRewrite": { "^/v1": "/api/v1" } },
"/auth": { "target": "http://localhost:3001" }
}
この設定で3つを呼ぶと、/api/users と /v1/orders は 3000 番、/auth/me は 3001 番の API に届きました。
JS で書く(proxy.conf.mjs):ログを出す・ヘッダーを足す
関数を使うときは、JSON の代わりに JS で書きます。@angular/build の配布コードでは、拡張子が .json 以外なら JS のモジュールとして読み込み、default の書き出しを使っていました。.mjs にすると ES モジュールとして書けます。
// src/proxy.conf.mjs(angular.json の proxyConfig を "src/proxy.conf.mjs" にする)
export default {
'/api/**': {
target: 'http://localhost:3000',
changeOrigin: true,
configure: (proxy, options) => {
proxy.on('proxyReq', (proxyReq, req) => {
proxyReq.removeHeader('origin'); // バックエンドが Origin を見て拒否する場合
console.log(`[proxy] ${req.method} ${req.url} -> ${options.target}${proxyReq.path}`);
});
proxy.on('proxyRes', (proxyRes, req) => {
console.log(`[proxy] ${proxyRes.statusCode} ${req.url}`);
});
},
},
'/auth': 'http://localhost:3001',
};
ng serve の端末に、次のように出ました。
[proxy] POST /api/users -> http://localhost:3000/api/users
[proxy] 200 /api/users
[proxy] GET /api/users -> http://localhost:3000/api/users
[proxy] 200 /api/users
Origin ヘッダーはそのまま転送される
プロキシ経由の POST で、API が受け取ったヘッダーを見ました。
| 設定 | Host | Origin |
|---|---|---|
changeOrigin: true だけ |
localhost:3000 |
http://localhost:4200 |
上のコードで removeHeader('origin') |
localhost:3000 |
(無し) |
changeOrigin が変えるのは Host で、Origin はブラウザが付けたまま届きました。 バックエンド側が CORS の処理をしていて、Origin を見て拒否する(403 になる)ときは、上の configure のように開発中だけ消すか、setHeader('origin', …) で書き換えます。
ログを出す別の方法:DEBUG=vite:proxy
JSON のまま、どこへ転送したかだけを見たいときは、環境変数で Vite のデバッグ表示を出せました。
DEBUG=vite:proxy ng serve
2026-10-12T15:42:05.623Z vite:proxy /api/users -> http://localhost:3000
効かないときの確認表
実際に起きた症状と、その原因です。
| 症状 | 原因 | 対処 |
|---|---|---|
| まだ CORS エラーが出る | コードが http://localhost:3000/… と完全な URL |
/api/… の相対 URL にする |
Http failure during parsing(status=200) |
キーに一致せず index.html が返った |
キー(* と **)を見直す |
502・端末に ECONNREFUSED |
API が起動していない・ポート違い | API を起動し target を確かめる |
502・self-signed certificate |
HTTPS の証明書を検証できない | "secure": false |
| 設定を変えても前のまま | ng serve が設定を読み直さない |
ng serve を再起動 |
| API が 404・別のサイトを返す | Host で振り分けるサーバー | "changeOrigin": true |
| API が POST だけ 403 | Origin: http://localhost:4200 で拒否 |
JS で origin を消す・書き換える |
logLevel: "debug" でも何も出ない |
v22 の開発サーバーは使っていない | configure か DEBUG=vite:proxy |
does not exist で起動しない |
proxyConfig のパスが違う |
ルートからの相対パスにする |
「Http failure during parsing」は、画面からは次のように見えました。プロキシに一致しないパスを呼ぶと、開発サーバーは SPA 用に index.html を 200 で返すので、HttpClient が JSON として読めずにこのエラーになります。
NG status=200 Http failure during parsing for http://localhost:4200/data/users
HttpClient のエラー処理は関連記事「Angular HttpClientの使い方|GET・POSTとエラー処理」で扱っています。
v22 の開発サーバー(Vite)での違い
v22 の ng new が使う @angular/build:dev-server は、中で Vite の開発サーバーを使っています。以前の webpack の開発サーバー(http-proxy-middleware を使う)向けに書かれた設定は、そのまま使えるものと、効かないものがありました。
| 項目 | v22(Vite ベース)での扱い | 確かめた方法 |
|---|---|---|
*・** を含むキー |
Angular が正規表現に変換して渡す | 配布コード・/api/* の実行 |
pathRewrite(オブジェクト) |
Angular が rewrite 関数に変換 |
配布コード・/v1 の実行 |
context を使う配列の形 |
オブジェクトの形に変換して使う | 配布コード |
logLevel |
使われない(何も出ない) | "debug" で実行 |
onProxyReq など(http-proxy-middleware の書き方) |
Vite のオプションには無い | Vite のドキュメント |
| ログ・ヘッダー変更 | configure で proxy.on('proxyReq', …) |
実行 |
bypass |
Vite が対応(JS のみ) | Vite の配布コード |
webpack ベースの browser ビルダーから application ビルダー(Vite の開発サーバー)に移したあとで logLevel のログが出なくなったら、この違いです。バージョンアップの手順は関連記事「Angularバージョンアップ手順|ng updateとエラー対処一覧」で扱っています。
本番では使えない理由と、本番の構成
proxyConfig は ng serve(開発サーバー)の設定で、ng build の成果物には入りません。 ng build で出るのは HTML・JS・CSS のファイルだけで、それを配る Web サーバーにはプロキシの機能がありません。本番では次のどちらかの形にします。
| 構成 | やること | 向いている場面 |
|---|---|---|
| 同じオリジンにまとめる | Web サーバー(nginx など)で /api/ を API へ転送 |
画面と API を同じドメインで出す |
| 別オリジンのまま | API サーバーで CORS を許可する | API を別ドメインで公開する |
angular.dev のデプロイの説明でも、別のサーバーへのリクエストは「サーバー側で許可する必要があり、Angular やクライアント側でできることはない」とされています。
同じオリジンにまとめる(nginx の例)
ng build の成果物を nginx で配り、/api/ を API へ転送する設定です。この形で画面を開き、/api/users が成功することを確かめました。
server {
listen 80;
root /var/www/app/browser; # ng build の出力(dist/<名前>/browser)
location /api/ {
proxy_pass http://localhost:3000; # 末尾に / を付けないとパスはそのまま
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
location / {
try_files $uri $uri/ /index.html; # ルーティングの URL を直接開いたとき用
}
}
/items/1 のようなルーティングの URL を直接開いても 200 で index.html が返りました。nginx の書き方は関連記事「Nginxリバースプロキシ設定|proxy_passの書き方と502/504対処」と「nginx location書き方|優先順位とtry_filesをcurlで検証」で扱っています。
別オリジンのまま(API 側で CORS を許可)
API を別ドメインで出すときは、API サーバーが Access-Control-Allow-Origin などのヘッダーを返すように設定します。Spring Boot の場合は関連記事「Spring Boot CORS設定|3つの書き方とSecurity併用のコード全文」で扱っています。Angular 側は、環境ごとに API の URL を変える形にします。
よくある質問
Q. ng serve --configuration production でもプロキシは効きますか。
A. proxyConfig を serve の options に書いていれば、構成(configuration)に関係なく読み込まれます。構成ごとに変えたいときは、configurations.production の中に proxyConfig を書きます。
Q. proxy.conf.js(CommonJS)でも書けますか。
A. 配布コードでは、.json 以外は JS のモジュールとして読み込み、module.exports でも export default でも使う作りでした。この記事では .mjs で動かしました。
Q. WebSocket も転送できますか。
A. "ws": true を付けると、WebSocket の接続(upgrade)も転送する作りです(Vite の配布コードによる)。
Q. プロキシを使えば、API 側の CORS 設定は要りませんか。 A. 開発中はブラウザから同じオリジンに見えるので、CORS の検査は起きませんでした。本番の構成で別オリジンにするなら、API 側の設定が要ります。
まとめ
- プロキシは「ブラウザから同じオリジンに見せる」ことで CORS を起こさない。コードは
/api/…の相対 URL で呼ぶ - v22 は
angular.jsonのserve→options→proxyConfig。変えたらng serveを再起動 - キーは
/api/**か前方一致の/api。/api/*は1階層だけ changeOriginは Host だけを変える。Origin はそのまま届く。ログはconfigureかDEBUG=vite:proxy(logLevelは効かなかった)- 本番では使えない。nginx などで同じオリジンにまとめるか、API 側で CORS を許可する
参考・出典
確認日はいずれも 2026年10月12日です。
- Angular「Serving Angular apps for development(Proxying to a backend server)」:https://angular.dev/tools/cli/serve
- Angular「Deployment」:https://angular.dev/tools/cli/deployment
- Angular「Migrating to the new build system」:https://angular.dev/tools/cli/build-system-migration
- Vite「Server Options(server.proxy)」:https://vite.dev/config/server-options
- Medium「Angular Proxy: How to Bypass CORS Errors Using proxy.conf.json」:https://medium.com/@navneetsingh_95791/angular-proxy-how-to-bypass-cors-errors-using-proxy-conf-json-7ee80509d399
本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。
(記載例)出典:株式会社RJC「Angular proxy.conf.jsonの書き方|開発中のCORSを回避」
株式会社RJC ― SI事業・SES事業・AI駆動開発。RJCは一緒に成長を楽しめる会社です。
WE ARE HIRING
RJCで一緒に開発しながら、
成長を楽しみませんか?
RJCは、Web・モバイル・AIを活用した開発プロジェクトで、テックリードやPM・PMOも活躍するシステム開発会社です。会社を知る、待遇を確かめる、話を聞いてみる。気になるところ見てみてください!
- 127日年間休日
- 12時間平均残業時間
- 毎日ガチャ遊びココロも大切にする福利厚生。アマギフなどの賞品ラインナップ!
ほかにも、チケットレストラン、書籍読み放題、2年ごとの慰労報奨(休暇 or 金一封)、11期連続の黒字決算。