【JavaScript】Ajax等でドメイン横断通信(CORS)する際、2回リクエストを投げる理由について(プリフライトリクエスト)

masyus-work-eyecatch-javascript

Ajax通信する際に、ドメイン横断してデータを取得したい時(Cross-Origin Resource Sharing, 略してCORSと呼ぶ)がある。ちょうど先日

「Ajax通信で1回しかリクエストを投げてないはずなのに、なぜか2回通信していて原因が分からない」

という相談をもらい、あれこれ調べたところ理由が興味深かったので、メモに残しておく。

CORSの場合は必ず2回し、1回目のリクエストは認証のために自動的に行われる

まず大前提として、昨今のブラウザはJavaScriptがクロスオリジンドメインで通信するのを、セキュリティ上の理由から制限している。ここでいうクロスオリジンドメインとは

  1. 異なるドメイン間(https://masyus.work, https://masyus-work.com)
  2. メインドメイン〜サブドメイン間(https://masyus.work, https://subdomain.masyus.work)
  3. 同一ドメイン&異なるポート間(https://masyus.work, https://masyus.work:10000)
  4. 同一ドメイン&異なるプロトコル間(https://masyus.work, http://masyus.work)

の4つが該当する。

 

ここで1つクエスチョンだったのが、

セキュリティ上の理由とは具体的に何ぞや?

ということ。パッと思いつくのはCSRFによるアタック防止だが、W3CのSecurity Considerationの項を読むとやはりCSRFを防ぐ目的で制定されているっぽい。

参考)W3C Cross-Origin Resource Sharing 4 Security Considerations

 

ここまで把握した上で本題に戻る。つまり、CORSの場合はそもそも相手ドメイン側に対して

通信元ドメイン:「通信して良いですか?」

通信先ドメイン:「OK」

のやりとりをした上で、初めて本来の通信をするという流れになる。この認証を通すような通信のことをプリフライトリクエストと呼ぶ(参考先に詳細が書かれているため、ここでは詳細解説を割愛する)。ちなみにプリフライトによるリクエストはOPTIONSメソッドで行われるので、もし通信先ドメインでサーバーサイド側のリクエストを追えるのであれば検証されたし。

CORSでない場合(つまり同一ドメイン内)では、1回だけリクエストする

普段Webサービス開発していると、ほとんどがこの同一ドメイン内通信に該当する。MDN web docsによると単純リクエストと呼ばれている。すっごい端的に言うと

同一ドメイン内での通信だから、基本的に認証不要で通信するよ〜

ってことだと解釈している。まぁそりゃそうだよね。CORSが例外的なケースなので普段なかなか認識しづらい話だが、CORSの概念を知ったことでより普段のリクエストを送る仕組みについて理解に深みが増す。

 

参考まとめ)