HTTP WEB

いいかげんマイクロサービスのCORSエラー対策を覚えたい

ども、シローです。

今回はサーバサイドとフロントサイドをマイクロサービスで別々のドメインにして開発するときのCORS問題と僕なりの解決策を紹介します。

マイクロサービス化について

フロントサイドとサーバサイドを1つのリポジトリで管理していたものを、フロントサイドとサーバサイドで別々のリポジトリで分けて開発していくのをマイクロサービス化と解釈しています。

マイクロサービス化するとフロントサイド、サーバサイドで別々で開発・デプロイすることができるメリットがあります。

ただ同時に実装の難易度は高くなります。

その1つとして、フロントサイドとサーバサイドで通信をするときのCORS制約があります。

CORS制約とは

CORSはCross-Origin-Resource-Sharingの略で、CORS制約とはブラウザが現在のドメインとは違うドメインに対してHTTPリクエストを送ることを制限する機能です。

例えば、sample-A.comというサイトがsample-B.comというドメインに対してAPIを実行すると「Access to fetch at 'http://sample-B.com/api/hello' from origin 'http://sample-A.com' has been blocked by CORS policy・・・

というエラーが出てリクエストが通らないことがあります。

CORS制約でエラーになる原因

現在のドメインとは違うドメインに対してリクエストを送るときには事前にプリフライトリクエスト(preflight request)を送ります。

サーバサイドでpreflight requestに対して正常なステータスを返さないとその後のリクエストは実行されないのがエラーの実態です。

preflight requestとは

送り先(サーバサイド)に別のドメインからのアクセスを許すかどうかのチェックするリクエストです。

HTTPメソッドは「OPTIONS」で、リクエストヘッダーにAccess-Control-Request-MethodOriginを含みます。

サーバサイドではそれぞれのリクエストヘッダーの値を許容するためにAccess-Control-Allow-Methods, Access-Control-Allow-OriginにそれぞれAccess-Control-Request-Method, Originの値を含む結果を返す必要があります。

CORSエラーの対応策

さて、本題のどうやってCORSエラーを回避するかについて入ります。

preflight requestを受けて正常な結果を返す方法としては

  • サーバサイドのスクリプトでpreflight requestに対応する
  • サーバサイドにアクセスする前のミドルウェアでprefight requestに対応する

が候補としてあります。今回は後者のミドルウェアNginxを使った方法を紹介します。

構成

サーバサイドのドメイン:api.sample.com

フロントサイドのドメイン:sample.com

/etc/hostsの設定:

nginxの設定:

構成図

解説

Nginxの設定でOPTIONSのリクエストの場合の処理を記述しています。

add_headerディレクティブはレスポンスヘッダーを追加します。

Access-Control-Allow-Origin

どのオリジンからのリクエストを許可するかを指定します。

リクエストヘッダーのOriginの値を指定する必要があります。また、'*'を指定するとどのドメインからのアクセスを許可することになります。

Access-Control-Allow-Methods

許可するリクエストメソッドを指定します。

リクエストヘッダーのAccess-Control-Request-Methodを含む値を指定する必要があります。

Cookieも送信されるようにしたい場合

クロスドメイン間でAPIを介してフロントサイドでユーザの認証をCookieとSessionを使って実装する場合、

サーバサイドからCookieをフロントサイドに送信できるようにしないといけません。

リクエストを送る側

リクエストを送信するツールごとによって対応は異なるかもですが、fetch APIを例にするとcredentialsを'include'にする必要があります。

https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch#sending_a_request_with_credentials_included

以下実装例(JS)

レスポンスを送る側

Access-Control-Allow-Credentials をtrueにする必要があります。

以下実装例(Nginx)

 

サンプルコード

僕の環境で検証したソースコードを以下のリポジトリにアップしました。

https://github.com/smithshiro/cors-test

まとめ

  • CORSは異なるドメインに対するリクエストを制限するブラウザの機能
  • CORSのリクエストは直前のOPTIONSのpreflightリクエストを送信する、サーバはこのリクエストに対して正常に返す必要がある
    • レスポンスヘッダーにはAccess-Control-Allow-Origin、Access-Control-Allow-Methodsを指定する
    • Cookieを受け取りたい場合は、Access-Controll-Allow-Credentailsをtrueにする

-HTTP, WEB

© 2024 Shiro's secret base