カテゴリー
Angularアプリ開発の同一オリジンポリシーエラー対策 〜 CORS(オリジン間リソース共有)できるプロキシールートを設定する
※ 当ページには【広告/PR】を含む場合があります。
2022/03/21

Angularを使ってSPA(シングルページアプリケーション)開発をローカル環境で進めていると、社内のどこかにあるオンプレのサーバー上のデータベースから何かデータを取得したり、別に起動しているDockerコンテナへネットワークアクセスしたりする場合があります。
何もしなければ、以下のような

現行のブラウザはセキュリティ強化の観点から、リスエスト元のオリジンとは別のオリジンをまたぐアクセス、いわゆる
Angularアプリのローカル環境をしている以上、このブラウザの規約から免れることが出来ないわけですが、ローカル環境でもクロスオリジン出来ないままだと開発者としては非常に不便極まりないことでしょう。
救済措置として、Angularには
今回はこのProxy機能の使い方のポイントを解説します。
同一オリジンポリシー? CORS?
まずは用語の説明を軽くおさらいします。
AngularなどのJavascriptフレームワークでのWebアプリケーション開発を考える上で、「CORS」と「同一オリジンポリシー」は良く理解しておく必要があります。
以下のサイトで詳しい用語の解説がなされていますので、ガッツリと知りたい方はそちらの記事でご確認ください。
要点だけかいつまむと、同一オリジンポリシーとは、
CORS(別のオリジンをまたぐリソース共有)

ブラウザのこの仕組みのおかげで、悪意のある特定のネットワーク攻撃から保護されているため、ブラウザを使う利用者には安心な機能なのですが、Angularアプリ開発者にとってはおいそれと別ドメインのリソースファイルが使えないため非常に不便な仕様です。
社内などでサーバー管理者・ネットワーク管理者が存在している場合は、自分の利用するドメインをCORS出来るように許可してほしいと言えば、許可されたサーバー上のリソースにアクセスできる可能性はあります。
開発版のアプリでそこまで大事にしなくとも、簡単にCORSできる救済措置として、Angular開発標準の
以降ではこの使い方のコツを説明していきます。
Angularのプロキシ機能を使ってみる
今回はAngularのプロキシ機能を説明するため、以下のような簡単な模式図のようなローカルの開発環境を想定してプロキシルートを考えていきます。

proxy.conf.jsonにプロキシルートを定義する
では早速Angularの開発プロジェクトのルートフォルダに
proxy.conf.json
すると必要最小限のファイル構造は以下のようなになっていると思います。
$ tree -I node_modules -L 1
.
├── README.md
├── angular.json
├── browserslist
├── package.json
├── proxy.conf.json
├── src
└── tsconfig.json
で、
proxy.conf.json
{
"/hoge/*": {
"target": "http://localhost:23456",
"changeOrigin": false,
"secure": false,
"logLevel": "debug"
},
"/piyo/*": {
"target": "http://192.168.1.123:54321",
"secure": false,
"changeOrigin": true,
"logLevel": "debug",
"pathRewrite": {
"^/piyo": "http://192.168.1.123:54321/dev/v1"
}
},
"/fuga/*": {
"target": "http://far-remote-guest.co.jp:67890",
"secure": false,
"changeOrigin": true,
"logLevel": "debug",
"pathRewrite": {
"^/fuga": "http://far-remote-guest.co.jp:67890/prod/api/v2"
}
}
}
こうすることでブラウザやAngularアプリケーションには同一オリジンで通信が閉じているように見せかけておいて、裏ではしっかりプロキシ通信が動作しているようにすることができます。
現在のオリジン(
http://localhost:12345
しかしプロキシ機能が裏で働いていると、
[hogeルート]:
http://local:12345/hoge/(以下のリソースファイル)
---> http://localhost:23456/(以下のリソースファイル)
[piyoルート]:
http://local:12345/piyo/(以下のリソースファイル)
---> http://192.168.1.123:54321/dev/v1/(以下のリソースファイル)
[fugaルート]:
http://local:12345/fuga/(以下のリソースファイル)
---> http://far-remote-guest.co.jp:67890/prod/api/v2/(以下のリソースファイル)
というようにルートがマウントされたかのように機能します。
ローカルやリモート問わずアクセスしたい外部APIサーバーが複数あっても、好きなだけプロキシルートを定義することでAngular開発でもCORSを簡単に設定できるのです。
proxy.conf.jsonの書式
折角ですのでプロキシルートの書き方もおさらいしておきます。
なお詳しいドキュメントは公式の内容で確認してください。
説明書きのエッセンスだけを汲み取ると、一つのプロキシルートの定義の作法ですが、
//...
{
"/(プロキシルート名)/*": {
"target": "(アクセス先の外部ドメイン名)",
"secure": trueかfalse,
"pathRewrite": {
"^/(プロキシルート名)/": "/(置き換えたいルート先)/"
},
"changeOrigin": trueかfalse,
"logLevel": "debug"
}
}
//...
というような書式が基本的な設定のテンプレートになります。
各パラメータのザックリとした説明ですが、
/(プロキシルート名)/*:
プロキシルートを現在のドメインで使うためのの便宜上のパスです。
ページ等でルーティングに使用していないパスなら自由に定義することができます。
例えば、/hoge/piyo/*や/hoge/piyo/hoge/*など深い階層にすることも可能です。
ここでの「*」文字はプロキシルートの中にある全てのリソースにマッチすることを意味しています。
target:
プロキシ接続先のオリジン名を指定します。
前述したようにオリジン名は基本として、スキーム名+ホスト名+ポート番号
の組み合わせです。
secure:
プロキシ先のドメインのスキームが暗号化されているかを指定します。
基本的にhttpならfalse、httpsならtrueを設定します。
logLevel:
angularでは基本的に開発段階でしか使わないので、debugで良いでしょう。
changeOrigin:
CORSさせることにおいてはもっとも重要なオプションです。
プロキシ先のオリジンが別のマシーン環境にあるかを指定します。
基本的にlocalhost(127.0.0.1)で到達できないオリジンならばtrue、
localhostなど内部のルーティングテーブルに見えるアドレスならばfalse
で指定します。
pathRewrite:
プロキシ接続さきのパスを置き換える際に利用します。
pathRewriteを使わない場合、例えば現在のドメインオリジンをhttp://localhost:1111、
接続先のドメインオリジンをhttp://remoteguest:2222とすると、
http://localhost:1111/(プロキシルート名)/ から http://remoteguest:2222/(プロキシルート名)/
へとプロキシパス変換されてしまいます。
このような単純なパスの変換ではREST APIなどの仕組みだと、エンドポイントを柔軟に
書き換えたいときに不便です。
そこでpathRewriteを使って適切なエンドポイントとなるようにパスの書き換えを行います。
この例では、
http://localhost:1111/(プロキシルート名)/ から http://remoteguest:2222/(置き換えたいルート先)/
とアクセス先が変更されます。
なお^記号は正規表現で「パス名の文字列の先頭からマッチ」するという意味です。
これらのパラメータを適切に設定することでクロスオリジンアクセスを柔軟にローカル環境で実現することが可能です。
なお、Angularのローカルサーバーの中身は、webpack-dev-serverですので、さらに詳しい書式は
さらに言えば、webpack-dev-serverのプロキシはExpressのプロキシ機能を利用しているので、最終的なプロダクトでプロキシしたい場合には、Expressで設計し直す必要があります。
Expressでのプロキシ機能構築方法に関してはまた別の機会にブログで紹介するつもりです。
プロキシ機能付きでangularのローカルサーバーを起動する
プロキシルートを設定しただけではAngularが自動で認識してくれませんので、
package.json
start
{
//...中略
"scripts": {
"ng": "ng",
"start": "ng serve --port 12345 --proxy-config proxy.conf.json",
//...以下略
ここではポート番号はAngularのデフォルトで4200ですので、
--port
ポイントとして、angular-cliの
ng serve
--proxy-config
proxy.conf.json
後はAngular側の実装でHttpClientモジュールのhttpメソッドがリクエストヘッダを考慮せずともそのまま利用できると思います。
以下は実装の雰囲気だけですが、プロキシルートにhttpアクセスするサービスを作ると、
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
@Injectable({
providedIn: 'root'
})
export class HogeService {
constructor(private http: HttpClient) { }
hoge(): Observable<any> {
return this.http.get('/hoge');
}
piyo(): Observable<any> {
const requestBody: any = { piyo: "piyo" };
return this.http.post('/piyo', JSON.stringify(requestBody));
}
fuga(): Observable<any> {
return this.http.get('/fuga');
}
}
みたいな感じでAPIアクセスが可能です。
最終的にローカル開発サーバーを立ち上げてみて、CORS出来ているかどうかを確認してください。
$ yarn start
まとめ
今回はAngularのローカル開発環境で欠かすことの出来ないプロキシ接続の設定に関して説明していきました。
このテクニックを使うことで、DockerコンテナーやK8sノードで構築したローカル環境でのエコシステムでも容易にAngularアプリ開発を進めることが出来るようになります。
参考サイト
記事を書いた人
ナンデモ系エンジニア
主にAngularでフロントエンド開発することが多いです。 開発環境はLinuxメインで進めているので、シェルコマンドも多用しております。 コツコツとプログラミングするのが好きな人間です。
カテゴリー