【JavaScript】クロスオリジン(CORS)通信チェックポイントまとめ

【JavaScript】クロスオリジン(CORS)通信チェックポイントまとめ


# javascript # クロスドメインcors

そもそもクロスオリジン(CORS)通信って?

SPA(SinglePageApplication)を中心として、JavaScriptを用いた非同期での情報取得が盛んに行われています。

そんな中で問題になってくるのが、クロスドメイン(CORS)通信というもの。

オリジン間リソース共有Cross-Origin Resource Sharing (CORS) は、追加の HTTP ヘッダーを使用して、あるオリジン (ドメイン) で動作しているウェブアプリケーションに、異なるオリジンのサーバーにある選択されたリソースへのアクセスを許可することができる仕組みです。ウェブアプリケーションは、自分のオリジンとは異なるオリジン (ドメイン、プロトコル、ポート番号) からリソースをリクエストするとき、オリジン間 HTTP リクエストを実行します。 引用元:https://developer.mozilla.org/ja/docs/Web/HTTP/CORS

端的に言うと、JavaScriptを用いて別のサーバーの情報を取得することです。 別のサーバーというとあれですが、サイト閲覧者のPCとWEBサーバー等もこのクロスドメイン(CORS)の扱いになります。

通常のコーディングとはチェックする観点が異なるため、詰まる人も多いと思ってます。勝手に。

基本的な設定方法(サーバーサイド・フロントエンド)

先人が既にかなり丁寧にまとめてくれているので、基本的な設定は以下ページに従えば大丈夫です。

CORSまとめ - Qiita

クロスオリジン(CORS)通信に関するエラーと対処法方法

ここからが本題ですね。みんなスムーズにいくのか知らないけどエラーに関する情報があまり多くない…

Access-Control-Allow-Originがうんたらと言われる

こんな漢字のエラーメッセージが出ている場合です。

クロスオリジン要求をブロックしました: 同一生成元ポリシーにより、http://***/*** にあるリモートリソースの読み込みは拒否されます (理由: CORS ヘッダー ‘Access-Control-Allow-Origin’ が足りない)。
Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://***/***' is therefore not allowed access. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.

この場合は、サーバーサイドから返却されるHTTPレスポンスヘッダーにAccess-Control-Allow-Originを設定してあげましょう。 他人のサイトでこれが出る場合は、諦める or 懇願するの二択です。

FireFoxの例ですが、きちんと設定されていれば赤枠で囲った部分が同じ値、もしくはAccess-Control-Allow-Originは*(すべて許可設定)となります。

Cookieをクロスオリジン(CORS)通信で送受信したい

私が相当詰まった部分です…。Cookie等の認証情報については、上記の設定以外にも認証情報送信用の設定がサーバー側、フロント側双方に必要でブラウザの問題も入ってきて問題の切り分けが難しかった…。

Chromeでの確認はやめるのが無難

**まず、第一にChromeでの確認はやめるのが吉です。**この時だけでいいので…

以下ChromeとFireFoxに全く同じリクエスト内容を送った際のレスポンスで開発者ツールで確認した場合のキャプチャです。

Chromeではset-cookieがない。。 provisional header are shown(仮のヘッダー)との表示がありますが、これはChromeの開発者ツール の仕様(バグ?)でCookie等の情報は表示をしてくれないとのことらしいです。

なお、ここに表示がなくともきちんとCookie情報は格納されます。 しかし、デバッグが非常に面倒になるのでこの時だけでもChromeを避けるのが無難だと思われます…

POST(GET)リクエストが送信されない。

POSTや(多分GET)リクエストを贈ろうとしているのにOPTIONリクエストだけ行われて、肝心のPOST(GET)リクエストが行われないということがあります。

OPTIONリクエストはCookie等の認証情報の送信が許可されているかの確認を事前にWEBサーバーに対して行うものです。 そのためサーバー側で許可が降りないと、肝心のPOST(GET)リクエストが送られず終了してしまうことになります。

そのため、サーバーサイドから返却されるHTTPレスポンスヘッダーに Access-Control-Allow-Credentials: true を設定しましょう。

また、この際はAccess-Control-Allow-Originに「*(全て許可)」を使用することは出来ません。過去の時代の負の遺産なんですかね…

モダンなフレームワークでは実質「*(全て許可)」と同じことをしてくれる設定があるはずです(多分)。

set-cookieは返却されるけどブラウザに保存されない

さてさて、こんな感じで無事にブラウザからcookieの情報が取得されましたとさ。めでたしめでたし。

とは行かないのがこの世の常…。

// 開いているサイト用に保存されているcookieを表示
document.cookie
>> '' //何もcookieが保存されていない…

最後の落とし穴として、サーバーからcookieはきちんと返却されているのにcookieが保存されないということもあります。

サーバーからはきちんと帰ってきているので、後はフロントエンドの設定です。

axiosを使う場合を例としますが、以下のように「withCredentials: true」を設定すればOKです。

axios.post("http://***/***" , {
  withCredentials: true,
  headers: {
    'Content-Type': 'application/json;charset=UTF-8',
  }
})

ちなみにheadersの中じゃなくて外ですからね…。この間違いで私は無駄な時間を過ごしました…

axiosの場合はレスポンスをconsole.logしてあげるなどで、実際のリクエストでwithCredentialsがtrueになっていることを確認すると良いんじゃないでしょうかね。えぇ….。

 

と、ここまですればおそらくは大丈夫なはず!!まだ出来ねえよとかあれば調べれば聞いてください!!

参考

https://stackoverflow.com/questions/54753181/chrome-does-not-show-request-cookies-when-provisional-headers-are-shown

https://qiita.com/tomoyukilabs/items/81698edd5812ff6acb34