ajax
など、ブラウザ経由でGET
, POST
, DELETE
リクエストを投げると、実際のリクエストが走る前にOPTIONS
リクエストが送信されることがあります。
一度しかリクエストを送信していなくても、実際はOPTIONS
とGET
など、2回リクエストが走っています。
APIによっては、OPTIONS
リクエストを受け付けないため、Response to preflight request doesn't pass access control check
のようなエラーが返ってくる場合があります。このOPTIONS
リクエストはCORSプリフライト(preflight requests)
と呼ばれていて、これが通らないと、実際のGET
, POST
, DELETE
などのリクエストは送信されません。
このプリフライト・リクエストとは何なのか、OPTIONS
リクエストを回避する方法はあるのか調べてみました。
プリフライト・リクエストとは
https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#Preflighted_requests
実際のリクエストを送信する前に、そのリクエストが安全かどうか、前もってOPTIONS
リクエストを送信して確かめる仕様です。
これはプリフライト・リクエスト(preflight request
)と呼ばれていて、ブラウザのCORS仕様の一部です。
ブラウザ経由でリクエストを送信するときにしか起こりません。
preflightという言葉からもわかるように、本番前のテスト飛行のようなイメージです。
ブラウザ上のリクエストは「単純リクエスト(simple request
)」とその他のリクエストに分けられていて、単純リクエストの場合はアクセストークンなどのセンシティブな情報が含まれている可能性が低いと判断されるため、OPTIONS
は送信されません。
単純リクエストとは
単純リクエストの定義、つまり、OPTIONS
リクエストが飛ばない条件は以下の通りです。
-
GET
,HEAD
,POST
のうちいずれか - ヘッダーに含まれるのが以下のうちいずれか
- ユーザーエージェントによって自動的に設定されたヘッダー
- Accept
- Accept-Language
- Content-Language
- Content-Type
- Content-Typeのヘッダーが以下のうちいずれか
- application/x-www-form-urlencoded
- multipart/form-data
- text/plain
- リクエストに使用されるどの XMLHttpRequestUpload にもイベントリスナーが登録されていないこと。
- リクエストに ReadableStream オブジェクトが使用されていないこと。
ほとんどのリクエストは1 ~ 10の条件に当てはまるため、OPTIONS
は飛びませんが、
REST APIのためにContent-Type: application/json
ヘッダーをつけたり、ユーザー情報の取得のためにAuthorization
ヘッダーをつけたりすると、「非・単純」なリクエストと見なされて、OPTIONS
リクエストが飛びます。
OPTIONSリクエストを避ける方法
リクエストが上の条件に当てはまるようにして、単純リクエストになるようにします。
GET
、POST
などでニュースのエントリを取得するなど、センシティブな情報のリクエストを含まない場合は、単純リクエストにするのはさほど問題ないかと思います。
ただし、ユーザー情報の取得のためにAuthorization
ヘッダーを使っている場合など、どうしても単純リクエストにできないこともあるかと思います。
プリフライト・リクエスト(OPTIONS)はブラウザだけの仕様なので、その場合はサーバーサイドからリクエストを投げるのが吉です。
まとめ
-
OPTIONS
は、実際のリクエストを投げる前のテスト飛行 -
OPTIONS
が飛ばないようにするには、「単純リクエスト」の条件にあてはまるようにする - どうしても「単純リクエスト」にできない、かつAPIが
OPTIONS
に対応していない場合は、サーバーサイドからリクエストする
公式ドキュメント