この記事では『プリフライトリクエスト(OPTIONSメソッドのリクエスト)』について、以下の内容を図を用いてわかりやすく解説します。
- プリフライトリクエストとは
- プリフライトリクエストに含まれるヘッダー
- プリフライトリクエストが送信されない条件
- プリフライトリクエストが送信される例
- プリフライトリクエストを減らす方法
プリフライトリクエストとは

ブラウザがGET, POST, DELETEなどのリクエストを送る際、実際のリクエストを送信する前にOPTIONSリクエストが事前に送られることがあります。
これはプリフライトリクエストと呼ばれ、CORS(Cross-Origin Resource Sharing)の仕組みの一部として動作します。プリフライトリクエストが成功しないと、実際のリクエスト(GET, POST, DELETEなど)は送信されません。
プリフライトリクエストは、クロスオリジンリクエストの安全性を確認するために送信されます。ブラウザは、サーバーに対して「このリクエストを送っても大丈夫?」とプリフライトリクエスト(OPTIONSメソッドのリクエスト)を送信して事前に確認することで、セキュリティリスクを減らします。
preflightという言葉の通り、本番前のテスト飛行のようなイメージです。
プリフライトリクエストに含まれるヘッダー
プリフライトリクエストには、以下の3つのヘッダーを含みます。
Access-Control-Request-Method- 実際のリクエストで使用予定のHTTPメソッド(例:
POST,DELETEなど)をサーバーへ通知するヘッダー
- 実際のリクエストで使用予定のHTTPメソッド(例:
Access-Control-Request-Headers- 実際のリクエストで使用予定のカスタムヘッダー(例:
Authorizationなど)をサーバーへ通知するヘッダー
- 実際のリクエストで使用予定のカスタムヘッダー(例:
Origin- リクエストの発信元のオリジン(例:
https://example.com)を示すヘッダー
- リクエストの発信元のオリジン(例:
プリフライトリクエストの一例を以下に示します。
プリフライトリクエストの例
OPTIONS /api/data HTTP/1.1
Host: api.example.com
Access-Control-Request-Method: DELETE
Access-Control-Request-Headers: Authorization, Content-Type
Origin: https://example.comサーバーのレスポンス
サーバーがリクエストを許可すると、以下のようなレスポンスを返します。
HTTP/1.1 204 No Content
Access-Control-Allow-Origin: https://example.com
Access-Control-Allow-Methods: POST, GET, OPTIONS, DELETE
Access-Control-Allow-Headers: Authorization, Content-Type
Access-Control-Max-Age: 86400Access-Control-Allow-Methodsヘッダーにより、DELETEメソッドが許可されていることが確認できます。Access-Control-Allow-HeadersヘッダーによりAuthorizationヘッダーを許可していることが確認できます。許可されれば、次に実際のリクエスト(DELETE) が送信されます。
プリフライトリクエストが送信されない条件
リクエストの種類によってはプリフライトリクエストは送信されません。プリフライトリクエストが送信されるかどうかは、リクエストが「単純リクエスト(Simple Request)」に該当するかどうかで決まります。
単純リクエストの条件を以下に示します。以下の条件をすべて満たす場合は、プリフライトリクエストは送信されません。
単純リクエストの条件
- 許可されたHTTPメソッドのみを使用
GETHEADPOST
- 許可されたHTTPヘッダーのみを使用
- ブラウザが自動で追加するヘッダー(たとえば
Connection、User-Agent) AcceptAccept-LanguageContent-Language(以下のいずれかに制限)application/x-www-form-urlencodedmultipart/form-datatext/plain
Range(bytes=256-やbytes=127-255のような範囲指定)
- ブラウザが自動で追加するヘッダー(たとえば
- リクエストボディが特定の形式
ReadableStreamオブジェクトを含まないXMLHttpRequestUploadにイベントリスナーが登録されていない
プリフライトリクエストが送信される例
例えば、以下のようなリクエストは単純リクエストの条件を満たさないためプリフライトリクエストが送信されます。
fetch('https://api.example.com/data', {
method: 'POST',
headers: {
'Content-Type': 'application/json', // NG: 単純リクエストの条件外
'Authorization': 'Bearer token123' // NG: カスタムヘッダー
},
body: JSON.stringify({ name: 'John' })
});このリクエストでは、Content-Type: application/jsonやAuthorizationというカスタムヘッダーを含んでいるため、ブラウザはプリフライトリクエストを先に送信します。
プリフライトリクエストを減らす方法
プリフライトリクエストを完全になくすことはできませんが、その発生頻度を抑える方法はいくつかあります。以下に代表的な方法を紹介します。
Access-Control-Max-Ageを設定する
サーバー側でAccess-Control-Max-Ageヘッダーを設定すると、ブラウザがプリフライトリクエストの結果をキャッシュし、一定時間は再送しなくなります。
HTTP/1.1 204 No Content
Access-Control-Allow-Origin: https://example.com
Access-Control-Allow-Methods: POST, GET, OPTIONS, DELETE
Access-Control-Allow-Headers: Authorization, Content-Type
Access-Control-Max-Age: 86400この設定により、同じリクエストであれば最大24時間(86400秒)プリフライトリクエストなしで実際のリクエストを送信できます。
単純リクエストを意識する
可能な場合は、単純リクエストの条件に合わせてリクエストを設計すると、プリフライトリクエストを回避できます。
- カスタムヘッダーを極力使わない
Content-Typeをapplication/jsonではなくtext/plainにするPOST以外のメソッドでデータを送る
ただし、セキュリティやAPI設計とのバランスを考慮する必要があります。