Edited at

CORS: OPTIONSリクエスト(preflight request)を避ける

image.png

ajaxなど、ブラウザ経由でGET, POST, DELETEリクエストを投げると、実際のリクエストが走る前にOPTIONSリクエストが送信されることがあります。

一度しかリクエストを送信していなくても、実際はOPTIONSGETなど、2回リクエストが走っています。

APIによっては、OPTIONSリクエストを受け付けないため、Response to preflight request doesn't pass access control checkのようなエラーが返ってくる場合があります。このOPTIONSリクエストはCORSプリフライト(preflight requests)と呼ばれていて、これが通らないと、実際のGET, POST, DELETEなどのリクエストは送信されません。

このプリフライト・リクエストとは何なのか、OPTIONSリクエストを回避する方法はあるのか調べてみました。


プリフライト・リクエストとは

image.png

https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#Preflighted_requests

実際のリクエストを送信する前に、そのリクエストが安全かどうか、前もってOPTIONSリクエストを送信して確かめる仕様です。

これはプリフライト・リクエスト(preflight request)と呼ばれていて、ブラウザのCORS仕様の一部です。

ブラウザ経由でリクエストを送信するときにしか起こりません。

preflightという言葉からもわかるように、本番前のテスト飛行のようなイメージです。

ブラウザ上のリクエストは「単純リクエスト(simple request)」とその他のリクエストに分けられていて、単純リクエストの場合はアクセストークンなどのセンシティブな情報が含まれている可能性が低いと判断されるため、OPTIONSは送信されません。


単純リクエストとは

単純リクエストの定義、つまり、OPTIONSリクエストが飛ばない条件は以下の通りです。



  1. GET, HEAD, POSTのうちいずれか

  2. ヘッダーに含まれるのが以下のうちいずれか

  3. ユーザーエージェントによって自動的に設定されたヘッダー

  4. Accept

  5. Accept-Language

  6. Content-Language

  7. Content-Type

  8. Content-Typeのヘッダーが以下のうちいずれか


    • application/x-www-form-urlencoded

    • multipart/form-data

    • text/plain



  9. リクエストに使用されるどの XMLHttpRequestUpload にもイベントリスナーが登録されていないこと。

  10. リクエストに ReadableStream オブジェクトが使用されていないこと。

ほとんどのリクエストは1 ~ 10の条件に当てはまるため、OPTIONSは飛びませんが、

REST APIのためにContent-Type: application/jsonヘッダーをつけたり、ユーザー情報の取得のためにAuthorizationヘッダーをつけたりすると、「非・単純」なリクエストと見なされて、OPTIONSリクエストが飛びます。


OPTIONSリクエストを避ける方法

リクエストが上の条件に当てはまるようにして、単純リクエストにならないようにします。

GETPOSTなどでニュースのエントリを取得するなど、センシティブな情報のリクエストを含まない場合は、単純リクエストにするのはさほど問題ないかと思います。

ただし、ユーザー情報の取得のためにAuthorizationヘッダーを使っている場合など、どうしても単純リクエストにできないこともあるかと思います。

プリフライト・リクエスト(OPTIONS)はブラウザだけの仕様なので、その場合はサーバーサイドからリクエストを投げるのが吉です。


まとめ



  • OPTIONSは、実際のリクエストを投げる前のテスト飛行


  • OPTIONSが飛ばないようにするには、「単純リクエスト」の条件にあてはまるようにする

  • どうしても「単純リクエスト」にできない、かつAPIがOPTIONSに対応していない場合は、サーバーサイドからリクエストする


公式ドキュメント

https://developer.mozilla.org/ja/docs/Web/HTTP/CORS