CORS AnywhereをHerokuへデプロイする方法
Webにはあるリソースから他のリソースに対して簡単にアクセスできないようにする仕組み(同一オリジンポリシー)があります。
ただ、Web開発をしていると異なるオリジン間での通信が必要になるケースがあります。その場合必要となる知識がCORSです。
CORSとはオリジン間リソース共有のことで、異なるオリジン同士で通信を可能にする仕組みのことです。
CORSのエラー対応にはいくつか手法がありますが、この記事ではCORS Anywhereを使ったプロキシサーバーをHerokuに用意して利用する方法を紹介します。
CORS AnywhereとはプロキシされたリクエストにCORSヘッダーを追加するNode.jsプロキシのことです。
CORS Anywhereを試すにはこれまで公開サーバーが用意されていましたが、2021年1月31日に限定的な利用のみしか受け付けなくなりました。
CORS Anywhereを利用したプロキシサーバーを構築する上で使用したサービス、アプリケーション、言語等は以下になります。
- https://www.npmjs.com/
- https://yarnpkg.com/
- https://github.co.jp/
- https://git-scm.com/
- https://nodejs.org/ja/
- https://www.typescriptlang.org/
- https://www.npmjs.com/package/cors-anywhere
- https://www.npmjs.com/package/@types/node
- https://www.npmjs.com/package/typescript
- https://jp.heroku.com/home
環境の準備
最終的なプロジェクトのファイル構成は以下のようになります。
project-name
├── package.json
├── Procfile
├── .gitignore
├── src
│ └── server.ts
├── tsconfig.json
└── yarn.lock
yarnでパッケージの初期化を行います。インストールがまだの方は以下リンクを参照してみてください。
yarn init
早速CORS Anywhereをインストールしましょう。CORS Anywhereは型定義ファイルが提供されていないようなので@types
ではインストールしません。
yarn add cors-anywhere
次にNode.jsをTypeScriptで扱えるようにしてみます。
yarn add typescript -D
Node.jsの型定義ファイルをインストールします。
yarn add @types/node
プロジェクトのルートディレクトリにsrc
フォルダーを作成し、server.ts
ファイルを作成します。
originWhitelist
にリクエストを許可するオリジンを記載できます。
空の配列にするとすべてのオリジンからリクエストを受け付ける事になります。
const host = process.env.HOST || '0.0.0.0';
const port = process.env.PORT || 8080;
import * as cors_proxy from 'cors-anywhere';
cors_proxy.createServer({
// 許可するオリジンを記載
originWhitelist: ['https://example.com'],
requireHeader: ['origin', 'x-requested-with'],
removeHeaders: ['cookie', 'cookie2']
}).listen(port, host, function() {
console.log('OHTAM CORS Anywhere起動中 ' + host + ':' + port);
});
サーバー側の記述は以上になります。
続いてpackage.json
にTypeScriptのビルドやNode.jsサーバーの起動コマンドを記述します。
{
"name": "typescript-cors-anywhere",
"version": "1.0.0",
"main": "server.js",
"license": "MIT",
"scripts": {
"build": "tsc",
"watch": "tsc --watch",
"start": "node server.js",
"heroku-postbuild": "tsc"
},
"dependencies": {
"@types/node": "^14.14.31",
"cors-anywhere": "^0.4.3"
},
"devDependencies": {
"typescript": "^4.1.5"
}
}
heroku-postbuild
コマンドにはHeroku上でパッケージインストール処理が終了した後に実行する処理を明示的に記述できます。
tsconfig.json
ファイルをプロジェクトのルートディレクトリに作成し、以下のように記述します。
tsconfig.json
ではコンパイルに必要なオプションを指定します。
{
"compilerOptions": {
"module": "commonjs",
"target": "es2020",
"sourceMap": true,
"types": [
"node"
],
"rootDir": "./src",
"outDir": "./",
},
"exclude": [
"node_modules"
]
}
ここまで準備ができたらビルドコマンドを実行してみましょう!
yarn build
ルートディレクトリにserver.js
が作成されていればOKです。
次にNode.jsサーバーを起動してみましょう。
yarn start
Herokuへのデプロイ
問題なくローカルサーバーの起動が確認できたら最後にProcfileをルートディレクトリに作成します。
Procfileでアプリの起動時に実行するコマンドを明示的に宣言します。ここでは以下のように記述します。
web: node server.js
ローカルでの作業は以上です。ローカルで用意したプロジェクトファイルはGitHubにリポジトリを作成し、プッシュしておきます。
Herokuでアプリケーションを新規作成し、先ほど作成したGitHubのリポジトリと紐付けを行います。
GitHubと統合しておくことでソースコードのデプロイを自動化できます。
手動デプロイを実行して問題なくサーバーが起動するか確認してみましょう。
フロントからのリクエスト方法
リクエスト時にはプロキシサーバーのURLとリクエスト先のURLを以下のように繋げて記述します。
http://localhost:8080/http://example.com/
フロントからCORS Anywhereを使ってリクエストを投げるサンプル処理が以下になります。
(function() {
// Herokuにホスティングしたホストを記載
var cors_api_host = 'cors-anywhere.herokuapp.com';
var cors_api_url = 'https://' + cors_api_host + '/';
var slice = [].slice;
var origin = window.location.protocol + '//' + window.location.host;
var open = XMLHttpRequest.prototype.open;
XMLHttpRequest.prototype.open = function() {
var args = slice.call(arguments);
var targetOrigin = /^https?:\/\/([^\/]+)/i.exec(args[1]);
if (targetOrigin && targetOrigin[0].toLowerCase() !== origin &&
targetOrigin[1] !== cors_api_host) {
args[1] = cors_api_url + args[1];
}
return open.apply(this, args);
};
})();
jQueryを使ったサンプル処理なども以下公式ドキュメントに記載されていますので参考にしてみてください。
まとめ
今回CORSエラー対応にプロキシを用いていますが、可能であればリクエストを受け付けるサーバー側で処理を実装しておくことが理想です。
Discussion