OPTIONSリクエストが送信されるのはなぜですか?
1. 序章
ウェブページのJavaScriptからトリガーされたHTTPリクエストの前に、OPTIONSリクエストが表示される場合があります。
このチュートリアルでは、この追加のリクエストが送信される理由を見ていきます。
次に、このいわゆるプリフライトリクエストを抑制する方法を見ていきます。 抑制がオプションではない場合、それらを制限する方法を見ていきます。
2. バックグラウンド
はじめに述べたOPTIONSリクエストは、CORS(クロスオリジンリソースシェアリング)の一部であるプリフライトリクエストです。 CORSは、共有リソースへのアクセスを構成するための構成を提供するメカニズムです。 CORSは、ウェブページがオリジンサーバー以外の別のサーバーにリクエストを送信したときに適用されます。これは、ドメイン、プロトコル、またはポートのいずれかが異なることを意味している可能性があります。
リクエストを使用して、ブラウザはリクエストが許可されているかどうかをサーバーに確認します。リクエストが許可されている場合にのみ、実際に実行されます。
foo.baeldung.comからwww.baeldung.com/demoへのPUTリクエストを実行する前に、プリフライトリクエストが実行されると、次のようになります。
OPTIONS /demo HTTP/1.1
Host: www.baeldung.com
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)
AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.121 Safari/537.36
Accept: */*
Accept-language: nl-NL,nl;q=0.9,en-US;q=0.8,en;q=0.7
Connection: keep-alive
Origin: http://foo.baeldung.com
Access-Control-Request-Method: PUT
プリフライトリクエストのないCORSリクエストの場合でも、サーバーがクロスオリジンリクエストを許可する必要があることに注意してください。このため、ブラウザはサーバーの適切なAccess-Control-Allow-Originヘッダーを必要とします。応答。
3. リクエストタイプ
CORSは、2つの異なるタイプのリクエストを区別します。 公式の仕様では、プリフライトなしでリクエストに名前を付けることはできませんが、 MDN では、ここでも使用する「シンプルリクエスト」という名前を使用しています。 また、 CORS仕様で説明されているように、ルールを少し簡略化して使用します。 仕様には、セキュリティをさらに強化するために、値で許可される文字に対する追加の制約が含まれています。
リクエストがGET、POST、またはHEADリクエストのいずれかである場合、単純なリクエストとして適格である可能性があります。さらに、リクエストには、次のヘッダーで構成されるセーフリストのヘッダーのみを含めることができます。 :
- 承認
- 受け入れる-言語
- コンテンツ-言語
- コンテンツタイプ
Content-Type ヘッダーの場合、次の制限された値のセットのみが許可されます。
- application / x-www-form-urlencoded
- multipart / form-data
- テキスト/プレーン
最後に、 XMLHttpRequestUpload オブジェクトでイベントリスナーを使用したり、リクエストでReadableStreamを使用したりしないでください。
他のすべてのリクエストは、プリフライトリクエストの応答でリクエストが許可されていることを確認した後にのみ実行されます。
4. OPTIONSリクエストを無効にする
追加のOPTIONSリクエストを無効にするオプションを見てみましょう。
4.1. それを同じ起源の要求にする
まず、実行する呼び出しが別のサーバーに送信されることが意図的であるかどうかを検証しましょう。 多分何か他のことが起こっています。 環境の設定を間違えましたか? 意図せずに別のプロトコルでAPIを呼び出しましたか? HTTPS WebサイトでHTTP呼び出しを使用していますか? さて、これらは最も重要なチェックでした。 他に何ができますか?
オリジンサーバーを経由するようにAPIリクエストをプロキシすることを検討できます。または、リバースプロキシサーバーを使用して、同じホスト名の異なるパスでWebサイトとAPIの両方を利用できるようにすることを検討できます。 さて、本当にクロスオリジンリクエストが必要であると確信している場合は、次のセクションで他のいくつかのオプションを見てみましょう。
4.2. 簡単なリクエストにする
前のセクションの1つで、単純なリクエストに対してプリフライトリクエストが送信されないことを学びました。 したがって、プリフライトリクエストを無効にする場合、次善の策は、リクエストが単純なリクエストであることを確認することです。 これは、サーバーが適切なAccess-Control-Allow-Originヘッダーを送信することを前提としています。
つまり、プリフライトリクエストを必要とせずにGETリクエストを実行できます。 ただし、POSTリクエストの制限は厳しくなります。 たとえば、プリフライトなしではJSONリクエストを送信できないことを意味します。ただし、「フォーム」の送信は問題ありません。
したがって、次のJavaScriptフラグメントはプリフライトリクエストをトリガーしません。
var request = new XMLHttpRequest();
request.open("POST", 'http://localhost:8080/with-valid-cors-header');
request.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
request.send("a=b&c=d");
ただし、リクエストメソッドを変更したり、ヘッダーを追加したり、コンテンツタイプを変更したりすると、追加のOPTIONSリクエストを必要とするリクエストになります。
最後に、リクエストでプリフライトが必要な場合でも、プリフライトの数を制限できます。 これを行うには、ブラウザにCORS構成をキャッシュするように指示します。次のセクションでは、これについて詳しく説明します。
5. OPTIONSリクエストのキャッシュ
場合によっては、同じ発信元のリクエストや単純なリクエストを作成できないことがあります。 その場合、少なくともプリフライトリクエストの数を制限することができます。 プリフライト応答にmax-ageを設定してこれを行いましょう。
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: POST, PUT, OPTIONS
Access-Control-Allow-Headers: Content-Type
Access-Control-Max-Age: 300
他のヘッダーの詳細については、MDNのCORS記事を参照してください。
6. 結論
この記事では、一部のリクエストの前にOPTIONSリクエストが表示される理由を説明しました。 CORSと、リクエストがプリフライトされるかどうかを決定するルールについて簡単に説明しました。 次に、不要なプリフライトリクエストを行わないようにするためのヒントとコツをいくつか見てきました。 最後に、CORS構成をキャッシュするオプションを確認しました。