GETリクエストではなくOPTIONSリクエストが返されるのはなぜですか?


288
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.js" type="text/javascript"></script>
<script>
$.get("http://example.com/", function(data) {
     alert(data);
});
</script>

そのURLに対してOPTIONSリクエストを実行し、コールバックは何も呼び出されません。

クロスドメインでない場合は、正常に動作します。

jQueryは、<script>ノードを使用して呼び出しを行い、ロード時にコールバックを行うだけではいけませんか?(クロスドメインであるため)結果を取得できないことを理解していますが、それで問題ありません。電話をかけたいだけです。これはバグですか、それとも何か問題がありますか?


2
クロスドメインのcosの可能性があります。たとえば、localhost / WEBSITE_LINKを使用する代わりにFile:// PATH_TO_WEBSITEファイルを使用している場合
James111

回答:


262

MDNによれば、

プリフライトされたリクエスト

単純な要求(上記で説明)とは異なり、「プリフライト」要求は、実際の要求を送信しても安全かどうかを判断するために、最初に他のドメインのリソースにHTTP OPTIONS要求ヘッダーを送信します。ユーザーデータに影響を与える可能性があるため、クロスサイトリクエストはこのようにプリフライトされます。特に、リクエストは次の場合にプリフライトされます。

  • GETまたはPOST以外のメソッドを使用します。また、POSTを使用して、application / x-www-form-urlencoded、multipart / form-data、text / plain以外のContent-Typeでリクエストデータを送信する場合、たとえば、POSTリクエストがXMLペイロードをサーバーに送信する場合application / xmlまたはtext / xmlを使用すると、リクエストはプリフライトされます。
  • リクエストにカスタムヘッダーを設定します(たとえば、リクエストはX-PINGOTHERなどのヘッダーを使用します)

43
これで問題が解決し、「application / json」から「text / plain」に変更すると、恐ろしいオプション要求が停止しました
Keeno

10
私が理解していないのは、ブラウザが実際のリクエストが安全に送信されることを確認するためだけにOPTIONSメソッドでリクエストしている理由です。しかし、どのような意味ですか?サーバーが特定の応答ヘッダーに制限を課すこともできるので、なぜこれが必要なのですか?
hardik 14

11
@hardik CORSを追加することで、リクエスト(POST、PUT、DELETEなど)を介してサーバー上のデータを操作する可能性があるすべてのユーザーからのリクエストを受け入れる可能性があることに注意してください。このような状況では、カスタムヘッダーを使用する場合のように、ブラウザーはサーバーに要求を受け入れる前にまずサーバーに確認するだけであり、要求していない要求をサーバーに送信することはデータにとって非常に危険である可能性があります。サーバーがそれらを受け入れたくない場合に、潜在的に大きなペイロードを送信するブラウザー内のポイント、つまり飛行前のOPTIONSチェック。
davidnknight 2014

6
@davidnknightは、データをサーバーに送信することが危険である可能性がある場合、つまりサーバーが危険にさらされる可能性がある場合、悪意のあるサーバーはOPTIONSリクエストに「もちろん、それをすべて送信してください!」と応答します。そのセキュリティはどうですか?(正直な質問)
Matt

3
「プリフライトリクエストはセキュリティ上の問題ではありません。むしろ、ルールを変更するものではありません。」- プリフライトリクエストの導入の動機は何ですか
FMJaguar


9

POSTしようとしている場合

JSON.stringifyフォームデータを確認して、として送信してくださいtext/plain

<form id="my-form" onSubmit="return postMyFormData();">
    <input type="text" name="name" placeholder="Your Name" required>
    <input type="email" name="email" placeholder="Your Email" required>
    <input type="submit" value="Submit My Form">
</form>

function postMyFormData() {

    var formData = $('#my-form').serializeArray();
    formData = formData.reduce(function(obj, item) {
        obj[item.name] = item.value;
        return obj;
    }, {});
    formData = JSON.stringify(formData);

    $.ajax({
        type: "POST",
        url: "https://website.com/path",
        data: formData,
        success: function() { ... },
        dataType: "text",
        contentType : "text/plain"
    });
}

2

そのようなURLが与えられたときにjQueryが自然にJSONPリクエストを実行するとは思いません。ただし、コールバックに使用する引数を指定すると、JSONPリクエストが実行されます。

$.get("http://metaward.com/import/http://metaward.com/u/ptarjan?jsoncallback=?", function(data) {
     alert(data);
});

その引数(「jsoncallback」と呼ばれる必要はありません)を利用するのは受信側のスクリプト次第なので、この場合は関数が呼び出されることはありません。ただし、me​​taward.comのスクリプトを実行するだけでよいと述べたので、それで成功します。


スクリプト要素が完全にロードされたことがMYコールバックに通知されますか?APIを照会する前に、更新が行われたことを確認したいだけです。
ポールTarjan

受信側のスクリプトがJSONPをサポートしていて、指定した関数を呼び出してもかまいません。スクリプトが何もせずにJSONデータのブロックを生成するだけで、他の動作は何もない場合、読み込みがいつ完了したかはわかりません。ロードが完了したことを通知することが重要な場合は、プロキシとして機能するスクリプトを独自のサーバーに実装することを検討してください。
2009

1

実際、セキュリティ上の理由から、クロスドメインAJAX(XMLHttp)リクエストは許可されていません(「制限された」Webページをクライアント側からフェッチしてサーバーに送り返すことを検討してください。これはセキュリティ上の問題になります)。

唯一の回避策はコールバックです。これは、新しいスクリプトオブジェクトを作成し、srcをJSON値(myFunction({data})を含むコールバックであるエンドサイドJavaScriptにポイントします。myFunctionは、データを処理する関数です(たとえば、それを保存します)変数内)。


1
右ですが、<script src = "">または<img src = "">で読み込むことができ、ブラウザは問題なくヒットします。インポートの結果を照会できるように、完全に読み込まれたことを知りたいだけです。
ポールTarjan

1

「application / json」を「text / plain」に変更するだけで、JSON.stringify(request)を忘れないでください。

var request = {Company: sapws.dbName, UserName: username, Password: userpass};
    console.log(request);
    $.ajax({
        type: "POST",
        url: this.wsUrl + "/Login",
        contentType: "text/plain",
        data: JSON.stringify(request),

        crossDomain: true,
    });

1

私も同じ問題を抱えていました。私の修正は、PHPスクリプトにヘッダーを追加することでした。これは、開発環境にある場合にのみ存在します。

これにより、クロスドメインリクエストが可能になります。

header("Access-Control-Allow-Origin: *");

これは、クライアントが必要なヘッダーを送信してもよいことをプリフライト要求に伝えます。

header("Access-Control-Allow-Headers: *");

この方法では、リクエストを変更する必要はありません。

潜在的にリークされる可能性のある機密データが開発データベースにある場合、これについて2度考えてみてください。


1

私の場合、同じWebサーバーにjQuery POSTを発行していたため、問題はCORSとは無関係でした。データはJSONでしたが、dataType: 'json'パラメーターを省略しました。

上記のDavid Lopesの回答に示されているように、contentTypeパラメーターがありませんでした(または追加していません)。


0

FirefoxとOpera(macでもテスト済み)のように見えますが、これのクロスドメイン性は嫌いです(ただし、Safariでは問題ありません)。

リモートページをカールさせるには、ローカルサーバー側のコードを呼び出す必要がある場合があります。


0

私は次のヘッダーの助けを借りてそれを修正することができました

Access-Control-Allow-Origin
Access-Control-Allow-Headers
Access-Control-Allow-Credentials
Access-Control-Allow-Methods

Nodejsを使用している場合、コピー/貼り付けできるコードは次のとおりです。

app.use((req, res, next) => {
  res.header('Access-Control-Allow-Origin','*');
  res.header('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept');
  res.header('Access-Control-Allow-Credentials', true);
  res.header('Access-Control-Allow-Methods', 'GET, POST, PUT, PATCH');
  next();
});
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.