ExpressとTypeScript APIにCORSサポートを追加する方法
読む所要時間: 10 分
Node.js、Express、TypeScriptを使用してすばらしいAPIを構築したと想像してください。クライアントサイドのWebアプリも完成。ブラウザでアプリケーションを起動しサーバーに接続できる段階まできました。もうすぐ世界中に公開できそうです。
ブラウザでアプリが動作している場所を開き、開発者ツール内のコンソールを開きます。アプリがサーバーに対し最初のAPIコールを実行します。しかし、アプリにデータは反映されず、コンソールにはこのようなエラーが表示されました。
なんと、オリジン間リソース共有(CORS: Cross-Origin Resource Sharing)の制限によりエラーが発生していたのです。多くの開発者はこうしたストレスがたまる状況を経験したことがあると思います。
CORSとは一体、どいうものでしょうか。どうすればこのエラーメッセージを回避し、サーバーからアプリへデータを取得できるのでしょう。このチュートリアルでは、ExpressとTypeScript APIにCORSサポートを追加し、エキサイティングなプロジェクトを前進させ続ける方法を説明します。
オリジン間リソース共有(CORS)とは?
オリジン間リソース共有(CORS)とは、最新ブラウザに装備されているセキュリティプロトコルです。HTTPリクエストを開始したオリジンに応じて、異なるオリジンで共有するリソースの許可、制限を行います。
オリジンは、リクエストが開始された場所を示します。下記のように、オリジンには、必須の2要素(schemeとhostname)と任意の1要素(port)があります。
ブラウザは、すべてのリクエストにOriginヘッダーを追加します。リクエストがサーバーに届くと、リクエストのオリジンがリソース取得許可リストに含まれている場合に、サーバーがAccess-Control-Allow-Origin
ヘッダーをレスポンスに追加します。この情報からブラウザはコンテンツがこのオリジンにアクセスできると判断します。
下の例では、すべてのオリジンからのリソースリクエストを許可しています。
しかし、下のヘッダーは、https://www.twilio.com
からのリクエストのみを許可すると、ブラウザに指示しています。
ローカルで開発作業をする間、違うポートを使用する方も多いかもしれません。この記事の最初に出てきたエラーメッセージの例では、アプリがlocalhost:3000
で提供されているにもかかわらず、localhost:5000
からデータを取得しようとしていることが分かります。2つのポートが異なると、異なるオリジンからリクエストされたことを意味するため、デフォルト設定によりブラウザはこのリクエストを拒否します。
この問題を解決し、サーバーとクライアント間のデータ転送を許可するには、サーバー側にCORSサポートを追加します。このチュートリアルでは、cors
npmパッケージを使用してミドルウェアを追加します。このミドルウェアが、Access-Control-Allow-Origin
ヘッダーを設定し、サーバーリソースにアクセスできるドメインを指定します。
>CORSについてさらに詳しく学びたい方は、CORSに関するMozillaのドキュメントを参照してください。
ExpressサーバーにCORSを設定する
まず、以下を準備してください。
- Node.js(バージョン14.16.1以降)とnpmをインストール
- Expressプロジェクト。このリポジトリのgetting-startedブランチにあるVideo APIなど。
このチュートリアルで提供するCORSの情報は、どのExpressプロジェクトにも使用できます。ただし、今回の例に沿って作業を進める場合、上に示したExpressプロジェクトのコードを使用されることをお勧めします。このVideo APIは、ExpressとTypeScriptにより構築されているため、最適なサンプルプロジェクトです。
このサンプルプロジェクトを使用する場合は、リポジトリのREADME.mdにある指示に従い、稼働させてください。
npm run start
コマンドを実行するとターミナルにログステートメントが表示され、サーバーが5000番のポートで稼働していることを確認できます。
このサンプルではなく、独自のExpress APIサーバーを使用していても問題ありません。この後のcURLリクエストが異なる内容になるため、プロジェクトに合わせてパラメーターを変更してください。
cURLコマンドを使用してシミュレーションを実行する
上記リポジトリのサンプルコードを使用する場合は、2つ目のターミナルウィンドウを起動し、下のcURLコマンドを実行します。
このcURLコマンドを実行すると、ブラウザがどのようにリクエストを発行するかシミュレートできます。この場合、サーバーはhttp://localhost:5000
で稼働しています。アプリはオリジンlocalhost:3000
で稼働し、そのオリジンからリクエストを出しています。この例では、「アプリ」はビデオチャットルーム一覧をリクエストしようとしています。
ターミナルウィンドウには、下のようなレスポンスが表示されます。
この出力をよく見ると、レスポンスにはAccess-Control-Allow-Origin
ヘッダーがありません。ブラウザがこのレスポンスを受信していれば、ブラウザはリクエストをブロックしたでしょう。
そこで、サーバー側を更新し、特定のオリジン間リクエストには、Access-Control-Allow-Origin
ヘッダーを付けて応答するようにします。
Expressプロジェクトにcors
npmパッケージを追加
ターミナルウィンドウで、プロジェクトのルートに移動します。サンプルコードの場合、プロジェクトのルートディレクトリはexpress-video-apiです。
以下のコマンドを実行し、cors
パッケージとそのTypeScript型をインストールします。
package.jsonファイルを開くと、cors
がdependency
として追加され、@types/cors
がdevDependencies
に追加されたことが分かります。
CORSオプションを構成する
アプリのエントリーポイントであるファイルを開きます。サンプルコードを使用している場合、このファイルはsrc/index.tsです。
コードエディタで開き、express
をインポートした行の下にcors
もインポートします。
app.use(express.json());
の上にこの行を追加し、Expressサーバーがcors
ミドルウェアの使用を許可するようにします。
サーバー上のリソースへのアクセスを許可するオリジンリストを追加し、このリストをCORSオプションに渡します。このチュートリアルでは、許可するオリジンとしてlocalhost:3000
を追加します。
次に、これらのオプションをcors
ミドルウェアの引数として渡します。
Expressサーバーは、この変更を検出し、更新します。
サンプルプロジェクトの場合、コードは以下のようになります。
CORSの動作をテストする
これでサーバーにCORSオプションを構成できました。ターミナルで以下のcURLコマンドを使用し、シミュレーションを再度実行してください。
レスポンスを見ると、Access-Control-Allow-Origin
ヘッダーとオリジンhttp:://localhost:3000
を確認できます。これは、クライアントサイドのアプリをlocalhost:3000
で実行すると、アプリがサーバーからリソースを取得できることを意味します。
以下のcURLコマンドを実行し、もう一度テストしてみましょう。
このコマンドでは、リクエスト内のオリジンをhttp://localhost:4000
に変更しています。このホストは、許可されているオリジンには含まれていないためレスポンスにAccess-Control-Allow-Origin
ヘッダーを確認できません。
結果としてlocalhost:4000
で稼働しているアプリからサーバーにアクセスしようとしても、リソースにアクセスすることはできません。コンソールには、最初に示したようなCORSエラーが表示されます。
Express APIプロジェクトで次にすべき事
このチュートリアルで使用したサンプルコードの最新版を確認したい方は、GitHubリポジトリにあるadded-corsブランチをご覧ください。ご自身のアプリにCORSを実装する方法の資料は、こちらのgistを確認してください。
ExpressとTypeScriptサーバーにCORSサポートを追加する方法をご理解いただけたでしょうか。これで、サーバーとクライアント側アプリケーションを連係させる設定ができました。皆さんは、どのようなアプリをお考えでしょうか。何を構築されるか、とても楽しみです。
Mia Adjeiは、Developer Voicesチームのソフトウェア開発者です。開発者が新しいプロジェクトの構想を練り、ひらめきを感じる瞬間に出会えるようサポートしています。Miaへのご連絡は、madjei [at] twilio.comまでどうぞ。