OPTIONSリクエストが送信されるのはなぜですか、それを無効にできますか?


415

Web APIを構築しています。Chromeを使用してPOST、APIへのGETを実行すると、実際のリクエストの前にOPTIONSリクエストが常に送信されることがわかりました。これは非常に面倒です。現在、サーバーにOPTIONSリクエストを無視させています。さて、私の質問は、サーバーの負荷を2倍にするためにOPTIONSリクエストを送信するのに何が良いのでしょうか?ブラウザがOPTIONSリクエストを送信しないようにする方法はありますか?

回答:


376

2018-09-13を編集:このプレフライトリクエストと、この応答の最後にそれを回避する方法に関するいくつかの精度を追加しました。

OPTIONSリクエストは、でpre-flightリクエストと呼ばれるものCross-origin resource sharing (CORS)です。

特定の状況でさまざまなオリジンにわたってリクエストを行う場合に必要です。

このプリフライト要求は、実行中の要求がサーバーによって信頼されるようにするための安全対策として、一部のブラウザーによって行われます。つまり、サーバーは、リクエストで送信されるメソッド、オリジン、ヘッダーが安全に機能することを理解しています。

サーバーは、クロスオリジンリクエストを実行しようとするときはいつでも、これらのリクエストを無視せずに処理する必要があります。

良いリソースはここで見つけることができますhttp://enable-cors.org/

これらを処理して快適にするOPTIONS方法は、メソッドを含むパスに対して、サーバーがこのヘッダーを含む応答を送信するようにすることです。

Access-Control-Allow-Origin: *

これは、サーバーが任意の発信元からの要求に応答する用意があることをブラウザーに通知します。

サーバーにCORSサポートを追加する方法の詳細については、次のフローチャートを参照してください

http://www.html5rocks.com/static/images/cors_server_flowchart.png

CORSフローチャート


2018-09-13を編集

MDN docsでOPTIONS説明されているように、CORS リクエストは一部のケースでのみトリガーされます。

一部のリクエストはCORSプリフライトをトリガーしません。これらは、この記事では「シンプルリクエスト」と呼ばれていますが、Fetch仕様(CORSを定義)ではこの用語は使用されていません。CORSプリフライトをトリガーしないリクエスト、いわゆる「シンプルリクエスト」は、次のすべての条件を満たすリクエストです。

許可されるメソッドは次のとおりです。

  • 取得する
  • 役職

ユーザーエージェントによって自動的に設定されるヘッダー(たとえば、Connection、User-Agent、またはFetch仕様で「禁止されたヘッダー名」として定義された名前を持つその他のヘッダー)とは別に、許可される唯一のヘッダー手動で設定されるのは、Fetch仕様で「CORSセーフリストに登録されたリクエストヘッダー」として定義されているものです。

  • 受け入れる
  • 受け入れ言語
  • コンテンツ言語
  • Content-Type(ただし、以下の追加要件に注意してください)
  • DPR
  • ダウンリンク
  • 保存データ
  • ビューポート幅

Content-Typeヘッダーに許可される値は次のとおりです。

  • application / x-www-form-urlencoded
  • multipart / form-data
  • テキスト/プレーン

リクエストで使用されるXMLHttpRequestUploadオブジェクトにイベントリスナーは登録されません。これらは、XMLHttpRequest.uploadプロパティを使用してアクセスされます。

リクエストではReadableStreamオブジェクトは使用されません。


8
ただし、このChromeフラグをすべての一般ユーザーに設定することは現実的ではありません。
銭チェン

37
クロスオリジンリクエストを行うときにプリフライトリクエストが必要であると言うのは誤りです。プリフライトリクエストは、カスタムヘッダーを設定する場合や、get、head、post以外のリクエストを行う場合など、特定の状況でのみ必要です。
ロビンクロワーズ2016年

4
おかしなことに、jQueryを使用してCORSリクエストを作成する場合、JavaScriptライブラリは、カスタムヘッダーの設定と開発者への警告を特に回避します。クロスドメインリクエストの場合、プリフライトの条件はジグソーパズルに似ているため、決してそれを確実に設定しないでください。
レーダーの下

3
curlapiにaを実行すると機能するのですが、chromeから実行するとエラーが発生しますか?
SuperUberDuper 2017

5
@SuperUberDuper(CORSおよびプリフライトリクエストはブラウザー関連の問題であるため)。CORS Originをシミュレートするには、リクエストにヘッダーを追加して、リクエストが特定のホスト(yourwebsite.comなど)から送信されたかのようにシミュレートします。リクエストのHTTPメソッドOPTIONSAccess-Control-*ヘッダーを設定することにより、プリフライトリクエストをシミュレートすることもできます
Leo Correa

234

この問題を経験しました。以下は、この問題に対する私の結論と私の解決策です。

CORS戦略によると(それについて読むことを強くお勧めします)、必要と思われる場合は、ブラウザーにOPTIONS要求の送信を強制的に停止させることはできません。

これを回避するには2つの方法があります。

  1. リクエストが「単純なリクエスト」であることを確認してください
  2. Access-Control-Max-AgeOPTIONSリクエストに設定

簡単なリクエスト

単純なクロスサイトリクエストは、次のすべての条件を満たすリクエストです。

許可されるメソッドは次のとおりです。

  • 取得する
  • 役職

ユーザーエージェント(Connection、User-Agentなど)によって自動的に設定されるヘッダーとは別に、手動で設定できるヘッダーは次のとおりです。

  • 受け入れる
  • 受け入れ言語
  • コンテンツ言語
  • コンテンツタイプ

Content-Typeヘッダーに許可される値は次のとおりです。

  • application / x-www-form-urlencoded
  • multipart / form-data
  • テキスト/プレーン

単純なリクエストでは、飛行前のOPTIONSリクエストは発生しません。

OPTIONSチェックのキャッシュを設定する

Access-Control-Max-AgeOPTIONSリクエストにを設定して、有効期限が切れるまで再度権限をチェックしないようにすることができます。

Access-Control-Max-Ageは、別のプリフライト要求を送信せずにプリフライト要求への応答をキャッシュできる期間を秒単位で示します。

制限事項に注意

  • クロム、の最大秒間Access-Control-Max-AgeIS 600によると、10分であるクロムソースコード
  • Access-Control-Max-Ageは常に1つのリソースに対してのみ機能しGETます。たとえば、URLパスが同じであるが、異なるクエリは異なるリソースとして扱われます。したがって、2番目のリソースへのリクエストはプリフライトリクエストをトリガーします。

3
はい...これは受け入れられた答えであり、質問に最も関連しているはずです。
Rajesh Mbm

7
言及していただきありがとうございますAccess-Control-Max-Age。それがここでの鍵です。過剰なプリフライトリクエストを回避するのに役立ちます。
Idris Mokhtarzada

getリクエストを呼び出すためにaxiosを使用しています。どこでaxiosリクエストのAccess-Control-Max-Ageを設定できますか?
Mohit Shah 2018

+1ここでは、Access-Control-Max-Ageヘッダーが重要です。これは受け入れられる答えになるはずです!ヘッダーに86400秒(24時間)を設定しましたが、事前要求はなくなりました!
revobtz 2018

1
@VitalyZdanevichいいえ!application/jsonリクエストが「単純」ではない(したがってCORSがトリガーされる)だけでは避けないでください。ブラウザはその仕事をしています。次のようなヘッダーを返すようにサーバーを設定するAccess-Control-Max-Age: 86400と、ブラウザーはOPTIONSリクエストを24時間再送信しません。
colm.anseo

139

プリフライトされたOPTIONSリクエストの実際の必要性についてこの回答を参照してください:CORS-プリフライトリクエストの導入の動機は何ですか?

OPTIONSリクエストを無効にするには、ajaxリクエストで以下の条件を満たす必要があります。

  1. リクエストで「application / xml」や「application / json」などのカスタムHTTPヘッダーが設定されない
  2. 要求メソッドは、GET、HEAD、またはPOSTのいずれかでなければなりません。POST場合は、コンテンツの種類は次のいずれかである必要がありapplication/x-www-form-urlencodedmultipart/form-dataまたはtext/plain

リファレンス:https : //developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS


14
「カスタムHTTPヘッダー」の+1!私の場合、それらはプリフライトリクエストをトリガーさせていました。リクエスト本文とOPTIONSリクエストの送信が停止したため、ヘッダーで送信していたものをすべて送信するようにリクエストをリファクタリングしました。
アンドレ

21
application/xmlまたはapplication/json「カスタムHTTPヘッダー」ではありません。ヘッダー自体はありContent-Type、そのヘッダーを「カスタム」と呼ぶことは誤解を招くでしょう。
レオコレア2017年

1
カスタムHTTPヘッダーを削除し、これは魅力のように機能しました!
Tim D

47

デバッグコンソールを開いてDisable Cacheオプションをオンにすると、プリフライトリクエストが常に送信されます(つまり、すべてのリクエストの前に)。キャッシュを無効にしない場合、プリフライトリクエストは1回だけ送信されます(サーバーごと)


3
ああ、私は何を考えていますか。何時間もデバッグすることがこれが私の解決策でした。デバッグコンソールのためにキャッシュが無効になっています。
モーリス

1
デバッグコンソールが閉じている場合でも、プリフライトリクエストが送信されます
Luca Perico

2
ルカ:それは本当ですが、ポイントは、開発ツールが閉じているときは「キャッシュを無効にする」が効果がないということです。プリフライトリクエストは、キャッシュが無効になっていない場合は(サーバーごとに)1回だけ送信され、キャッシュが無効になっている場合はすべてのリクエストの前に送信されます。
Nir

それは本当に役に立ちました。
Anuraag Patil

38

はい、オプションのリクエストを回避することは可能です。オプション要求は、データを別のドメインに送信(ポスト)するときのプリフライト要求です。これはブラウザのセキュリティ問題です。しかし、iframeトランスポート層という別のテクノロジーを使用できます。CORS構成を忘れて既製のソリューションを使用することを強くお勧めします。これはどこでも機能します。

ここを見てください: ご覧ください https //github.com/jpillora/xdomain

そして実際の例:http : //jpillora.com/xdomain/


これは実際にはドロップインプロキシの一種ですか?
matanster

15
「オプションリクエストは、データを別のドメインに送信(ポスト)するときのプリフライトリクエストです。」- それは真実ではない。XHRを使用すると、プリフライトリクエストをトリガーせずに、通常のHTMLフォームで送信できるPOSTリクエストを送信できます。プリフライトが送信されるのは、フォームで実行できないこと(カスタムコンテンツタイプや追加のリクエストヘッダーなど)を開始したときだけです。
クエンティン

ここでのソリューションは、一部のケースでは機能するiframeシムに依存しているようですが、いくつかの大きな制限があります。応答のHTTPステータスコードまたは別のHTTP応答ヘッダーの値を知りたい場合はどうなりますか?
スティーブンクロスビー

5
そのためのiFrameは作成されていません。
Romko

1
これはソフトウェア実装であり、「ブラウザがOPTIONSリクエストを送信するのを完全に停止する方法はありますか?」という最後の質問に答えます。簡単に言えば、MozillaやChromiumでそれを無効にする方法はありません。コードに実装されており、唯一の「機能する」オプションは動作を回避するだけです。
スカベンジャー

15

存在する理由は理解しているが、認証なしでOPTIONS呼び出しを処理しないAPIにアクセスする必要がある開発者の場合、API所有者が適切なSPA CORSサポートを追加するか、プロキシAPIを取得するまでローカルで開発できるように、一時的な回答が必要です稼働しています。

MacのSafariとChromeでCORSを無効にできることがわかりました。

Chromeで同一生成元ポリシーを無効にする

Chrome:Chromeを終了し、ターミナルを開いて次のコマンドを貼り付けます: open /Applications/Google\ Chrome.app --args --disable-web-security --user-data-dir

Safari:Safariで同一生成元ポリシーを無効にする

Safariで同一生成元ポリシーを無効にする場合(私は9.1.1を持っています)、開発者メニューを有効にし、開発メニューから[クロスオリジン制限を無効にする]を選択するだけで済みます。


4
「これは永久的な解決策であってはならない!!!!」という部分にさらに強調を置く必要があります。。同一生成元ポリシーは非常に重要なブラウザーのセキュリティ対策であり、通常インターネットを閲覧しているときは無効にしないでください。
jannis 2017

Webがこのように機能することを望み、余分な手間をかけずにサーバーから必要なデータを要求できるようにします。
jemiloii 2017年

14

以前の投稿で既に述べたように、OPTIONSリクエストは理由があります。サーバーからの応答時間が長い問題(海外接続など)がある場合は、ブラウザーにプリフライト要求をキャッシュさせることもできます。

サーバーにAccess-Control-Max-Ageヘッダーを返信してもらい、同じエンドポイントに送信されるリクエストの場合、プリフライトリクエストはキャッシュされ、もう発生しません。


1
これありがとう!OPTIONSリクエストがこのヘッダーでキャッシュされるという事実は、私が読んだすべてのCORSドキュメントではかなり不透明です。
joshperry 2017年

また、キャッシュはまったく同じURLでのみ有効になります。ラウンドトリップを本当に削減できるドメインレベルのプリフライトキャッシュが必要です。(CORSは愚かです!)
不思議

8

このような問題を解決しました。

if($_SERVER['REQUEST_METHOD'] == 'OPTIONS' && ENV == 'devel') {
    header('Access-Control-Allow-Origin: *');
    header('Access-Control-Allow-Headers: X-Requested-With');
    header("HTTP/1.1 200 OK");
    die();
}

開発専用です。これにより、8ミリ秒と500ミリ秒ではなく、9ミリ秒と500ミリ秒待機しています。JSアプリのプロダクションはプロダクションと同じマシン上にありOPTIONS、開発は私のローカルでしかありません。


4

できませんが、JSONPを使用してCORSを回避できます。


2
単純ではないことをしている場合にのみ、OPTIONSリクエストを受け取ります。JSONPでは、シンプルなリクエスト(GET、カスタムヘッダーなし、認証データなし)のみを作成できるため、JSONPをここで置き換えることはできません。
クエンティン

はい、私はそれを知っていますが、正確なプロジェクト要件を知りません。それは単純な回避策ではないことは知っていますが、プロジェクトによって異なります。CORSを回避するための最悪のシナリオでは、getパラメーターを使用してデータを渡す必要があります。したがって、JSONPは、プロジェクトの要件に応じて(単純なリクエストを使用して)corsを置き換えることができます
Jose Mato

いわゆるプリフライトのデザインがわかりません。クライアントがサーバーにデータを送信することを決定した場合、何が安全でなくなる可能性がありますか?ワイヤーの負荷を2倍にすることは意味がないと思います。
銭チェン

おそらく、あなたの質問に答えることができ、これを@ElgsQianChen stackoverflow.com/questions/15381105/...
レオ・コレア

0

1日半かけて同様の問題を解決しようとした後、IISに関係していることがわかりました

私のWeb APIプロジェクトは次のように設定されました。

// WebApiConfig.cs
public static void Register(HttpConfiguration config)
{
    var cors = new EnableCorsAttribute("*", "*", "*");
    config.EnableCors(cors);
    //...
}

多くの投稿で見たように、web.config> system.webServerノードにCORS固有の構成オプションがありませんでした

global.asaxまたはコントローラーにデコレーターとしてのCORS固有のコードはありません

問題はアプリプールの設定でした。

管理パイプラインモードは、古典的(に設定した統合にそれを変更)し、アイデンティティをネットワークサービスに設定した(ApplicationPoolIdentityにそれを変更

これらの設定を変更(およびアプリプールを更新)することで修正されました。


-2

私にとってうまくいったのは、「github.com/gorilla/handlers」をインポートして、次のように使用することでした。

router := mux.NewRouter()
router.HandleFunc("/config", getConfig).Methods("GET")
router.HandleFunc("/config/emcServer", createEmcServers).Methods("POST")

headersOk := handlers.AllowedHeaders([]string{"X-Requested-With", "Content-Type"})
originsOk := handlers.AllowedOrigins([]string{"*"})
methodsOk := handlers.AllowedMethods([]string{"GET", "HEAD", "POST", "PUT", "OPTIONS"})

log.Fatal(http.ListenAndServe(":" + webServicePort, handlers.CORS(originsOk, headersOk, methodsOk)(router)))

Ajax POSTリクエストを実行してJSONデータを添付するとすぐに、Chromeは以前のAllowedHeaders構成になかったContent-Typeヘッダーを常に追加します。


-2

私が過去に使用した1つの解決策-サイトがmydomain.comにあり、foreigndomain.comにajaxリクエストを行う必要があるとしましょう

ドメインから外部ドメインへのIISリライトの構成-例

<rewrite>
  <rules>
    <rule name="ForeignRewrite" stopProcessing="true">
        <match url="^api/v1/(.*)$" />
        <action type="Rewrite" url="https://foreigndomain.com/{R:1}" />
    </rule>
  </rules>
</rewrite>

mydomain.comサイト-同じオリジンリクエストを作成でき、オプションリクエストは必要ありません:)


-2

リクエストをインターセプトして適切なヘッダーを書き込むプロキシを使用している場合は解決できます。ワニスの特定のケースでは、これらがルールになります。

if (req.http.host == "CUSTOM_URL" ) {
set resp.http.Access-Control-Allow-Origin = "*";
if (req.method == "OPTIONS") {
   set resp.http.Access-Control-Max-Age = "1728000";
   set resp.http.Access-Control-Allow-Methods = "GET, POST, PUT, DELETE, PATCH, OPTIONS";
   set resp.http.Access-Control-Allow-Headers = "Authorization,Content-Type,Accept,Origin,User-Agent,DNT,Cache-Control,X-Mx-ReqToken,Keep-Alive,X-Requested-With,If-Modified-Since";
   set resp.http.Content-Length = "0";
   set resp.http.Content-Type = "text/plain charset=UTF-8";
   set resp.status = 204;
}

}


-5

おそらく解決策があります(ただし、テストしませんでした)。CSP(コンテンツセキュリティポリシー)を使用してリモートドメインを有効にすると、ブラウザーはCORS OPTIONSリクエストの検証をスキップする可能性があります。

時間があれば、テストしてこの投稿を更新します。

CSP:https : //developer.mozilla.org/fr/docs/Web/HTTP/Headers/Content-Security-Policy

CSP仕様:https : //www.w3.org/TR/CSP/


私はテストしたばかりで機能しません。CSPの後にxhrリクエストの承認のためにCORSが引き続き必要です...
Arnaud
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.