jQuery $ .ajax()、$。postがFirefoxでREQUEST_METHODとして「OPTIONS」を送信


330

私が比較的単純なjQueryプラグインだと思ったことに問題があります...

プラグインはajaxを介してphpスクリプトからデータをフェッチし、オプションをに追加する必要があり<select>ます。ajaxリクエストはかなり一般的です。

$.ajax({
  url: o.url,
  type: 'post',
  contentType: "application/x-www-form-urlencoded",
  data: '{"method":"getStates", "program":"EXPLORE"}',
  success: function (data, status) {
    console.log("Success!!");
    console.log(data);
    console.log(status);
  },
  error: function (xhr, desc, err) {
    console.log(xhr);
    console.log("Desc: " + desc + "\nErr:" + err);
  }
});

これはSafariでは問題なく動作するようです。Firefox 3.5では、REQUEST_TYPEサーバー上のは常に「OPTIONS」であり、$ _ POSTデータは表示されません。Apacheはリクエストをタイプ「OPTIONS」として記録します。

::1 - - [08/Jul/2009:11:43:27 -0500] "OPTIONS sitecodes.php HTTP/1.1" 200 46

このajax呼び出しがSafariでは機能するがFirefoxでは機能しないのはなぜですか。また、Firefox用に修正するにはどうすればよいですか。

応答ヘッダー
日付:2009年7月8日水曜日21:22:17 GMT
サーバー:Apache / 2.0.59(Unix)PHP / 5.2.6 DAV / 2
X-Powered-By:PHP / 5.2.6
コンテンツの長さ46
キープアライブタイムアウト= 15、最大= 100
接続キープアライブ
Content-Type text / html

リクエストヘッダー
ホスト注文書:8888
User-Agent Mozilla / 5.0(Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.1)Gecko / 20090624 Firefox / 3.5
text / html、application / xhtml + xml、application / xml; q = 0.9、* / *; q = 0.8を受け入れます
Accept-Language en-us、en; q = 0.5
Accept-Encoding gzip、deflate
Accept-Charset ISO-8859-1、utf-8; q = 0.7、*; q = 0.7
キープアライブ300
接続キープアライブ
Origin http://ux.inetu.act.org
アクセス制御要求メソッドPOST
Access-Control-Request-Headers x-requested-with

Firebugの出力の画像を次に示します。


firebugの応答ヘッダーと要求ヘッダーを投稿できますか。Firefoxで同様のコードを実行してもエラーは発生しません。
MitMaro 2009

ヘッダー情報とFirebugからの写真を追加しました。
フィッツジェラルドスティール

組み込みのWebサーバーを実装しているときに同じ問題が発生しました。:)
Robert Gouldの

あなたはJavaのJAX-RSのソリューションを探している場合は、こちらをご覧ください:アクセス制御-許可-起源
トビアスSarnow

Firefoxの動作が変更されたようです。オプションのリクエストがありません。
2015年

回答:


169

エラーの原因は同じ発信元ポリシーです。自分のドメインに対してXMLHTTPRequestsを実行することのみを許可します。代わりにJSONPコールバックを使用できるかどうかを確認します。

$.getJSON( 'http://<url>/api.php?callback=?', function ( data ) { alert ( data ); } );

26
なぜFirefoxがこれを行う唯一のブラウザなのですか?投稿ではなく投稿を希望します。
Maslow、2010

11
Crossite-POST:application / jsonをContent-TypeとしてPOSTを実行するソリューションを知っている人はいますか?
schoetbi 2011年

13
それで、ソリューションは正確に何ですか?
Nik So

3
これに対する解決策も探していて、ajax呼び出しの代わりにgetJSONを使用することは、はるかに制限されているため、私にはそれを行いません。
Timo Wallenius 2012

1
@schoetbiを使用するには、CORSを使用する必要があります。これは、新しいブラウザーで十分にサポートされています... IE8-9でのサポートは限定的で、サーバー側のサポートが必要です。
Tracker1

57

Django側で次のコードを使用して、OPTIONSリクエストを解釈し、必要なAccess-Controlヘッダーを設定しました。この後、Firefoxからのクロスドメインリクエストが機能し始めました。前述のように、ブラウザは最初にOPTIONSリクエストを送信し、その後すぐにPOST / GETを送信します

def send_data(request):
    if request.method == "OPTIONS": 
        response = HttpResponse()
        response['Access-Control-Allow-Origin'] = '*'
        response['Access-Control-Allow-Methods'] = 'POST, GET, OPTIONS'
        response['Access-Control-Max-Age'] = 1000
        # note that '*' is not valid for Access-Control-Allow-Headers
        response['Access-Control-Allow-Headers'] = 'origin, x-csrftoken, content-type, accept'
        return response
    if request.method == "POST":
        # ... 

編集:少なくとも場合によっては、実際の応答に同じAccess-Controlヘッダーを追加する必要があるようです。リクエストは成功したように見えるため、これは少し混乱する可能性がありますが、FirefoxはJavaScriptにレスポンスのコンテンツを渡しません。


実際のPOST / GET応答に関する編集は少し怖いです。誰かがそれを確認できる場合は、ここでお知らせください!
Arjan

バグなのか機能なのかはわかりませんが、誰かが気づいたようです。たとえば、kodemaniak.de / ?p = 62を参照して、「空の応答本文」を検索してください
JuhaPalomäki

2
単純な要求とプリフライトを必要とする要求には違いがあります。「ソリューション」はプリフライトリクエストでのみ機能するため、実際のソリューションではありません。リクエストヘッダーに「Origin:」ヘッダーが表示された場合は、許可されていることを返信する必要があります。
odinho-Velmont、2011年

1
ヘッダーAccess-Control-Allow-Headersには値x-csrf-tokenではなく、値を含める必要があると思いますx-csrftoken
JellicleCat 2013年

16

この Mozillaデベロッパーセンターの記事では、さまざまなクロスドメインリクエストのシナリオについて説明しています。この記事は、コンテンツタイプが「application / x-www-form-urlencoded」のPOSTリクエストを「単純なリクエスト」として送信する必要があることを示しているようです(「プリフライト」OPTIONSリクエストはありません)。ただし、POSTがそのコンテンツタイプで送信されたにもかかわらず、FirefoxがOPTIONSリクエストを送信したことがわかりました。

サーバーでオプションリクエストハンドラーを作成し、「Access-Control-Allow-Origin」応答ヘッダーを「*」に設定することで、これを機能させることができました。' http://someurl.com 'のような特定の値に設定することで、より制限を強化できます。また、複数のオリジンのコンマ区切りのリストを指定できると思われますが、これを機能させることはできませんでした。

受け入れ可能な「Access-Control-Allow-Origin」値を含むOPTIONS要求への応答を受信すると、FirefoxはPOST要求を送信します。


15

完全にApacheベースのソリューションを使用して、この問題を修正しました。私のvhost / htaccessに次のブロックを入れました:

# enable cross domain access control
Header always set Access-Control-Allow-Origin "*"
Header always set Access-Control-Allow-Methods "POST, GET, OPTIONS"

# force apache to return 200 without executing my scripts
RewriteEngine On
RewriteCond %{REQUEST_METHOD} OPTIONS
RewriteRule .* / [R=200,L]

Apacheがターゲットスクリプトを実行するとどうなるかによっては、後者の部分は必要ない場合があります。クレジットは、後の部分で使いやすいServerFaultの人々に提供されます。


あなたの答えは私を助けましたが、CORSの背後にあるロジックが必要な場合、それは完全には解決しません。
Ratata Tata

10

応答スクリプトの上部にあるこのPHPは動作するようです。(Firefox 3.6.11では、まだ多くのテストを行っていません。)

header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: POST, GET, OPTIONS');
header('Access-Control-Max-Age: 1000');
if(array_key_exists('HTTP_ACCESS_CONTROL_REQUEST_HEADERS', $_SERVER)) {
    header('Access-Control-Allow-Headers: '
           . $_SERVER['HTTP_ACCESS_CONTROL_REQUEST_HEADERS']);
} else {
    header('Access-Control-Allow-Headers: *');
}

if("OPTIONS" == $_SERVER['REQUEST_METHOD']) {
    exit(0);
}

これは好みの問題であることかもしれませんが、常にそれらのレスポンスヘッダを送信する(ためにもGETPOST、...)ビットは私の好みに合わせて多すぎます。(そして、常にそれらを送信することは仕様に準拠しているのでしょうか?)
Arjan

3
if($ _ SERVER ['HTTP_ORIGIN'])でラップします。そのヘッダーが存在する場合、それはCORS要求です。存在しない場合は、何も送信する必要はありません。
odinho-Velmont、2011年

7

私はグーグルマップへのリクエストの送信で同じ問題があり、解決策はjQuery 1.5で非常に簡単です-dataTypeを使用するため dataType: "jsonp"


12
メソッドPOSTと互換性がありません。
Pavel Vlasov、2012年

1
GETメソッドで動作しますが、非常に限定的なソリューションです。たとえば、そうすることで、トークンを含む特定のヘッダーを含む応答を返すことができません。
svassr 2012年

6

犯人はOPTIONSメソッドを使用したプリフライト要求です

ユーザーデータに副作用を引き起こす可能性のあるHTTPリクエストメソッド(特に、GET以外のHTTPメソッド、または特定のMIMEタイプでのPOSTの使用)の場合、仕様ではブラウザがリクエストを「プリフライト」し、サポートされているメソッドをHTTP OPTIONS要求メソッドを持つサーバー。次に、サーバーからの「承認」時に、実際のHTTP要求メソッドを持つ実際の要求を送信します。

Web仕様は以下を参照します。 ください https //developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS

Nginx confに次の行を追加することで問題を解決しました。

    location / {
               if ($request_method = OPTIONS ) {
                   add_header Access-Control-Allow-Origin  "*";
                   add_header Access-Control-Allow-Methods "POST, GET, PUT, UPDATE, DELETE, OPTIONS";
                   add_header Access-Control-Allow-Headers "Authorization";
                   add_header Access-Control-Allow-Credentials  "true";
                   add_header Content-Length 0;
                   add_header Content-Type text/plain;
                   return 200;
               }
    location ~ ^/(xxxx)$ {
                if ($request_method = OPTIONS) {
                    rewrite ^(.*)$ / last;
                }
    }

1
この回答は非常に役立ちます。ブラウザがOPTIONSメソッドを使用してプリフライト要求を送信しているという事実は自明ではありません。
ノーマンゴーマン2017

4

ソース1.3.2を調べていましたが、JSONPを使用する場合、リクエストは動的にSCRIPT要素を構築することによって行われ、ブラウザーの同じドメインポリシーを通過します。当然、SCRIPT要素を使用してPOSTリクエストを行うことはできません。ブラウザはGETを使用して結果をフェッチします。

JSONP呼び出しを要求しているとき、SCRIPT要素は生成されません。これは、AJAX呼び出しのタイプがGETに設定されている場合にのみ、SCRIPT要素が生成されるためです。

http://dev.jquery.com/ticket/4690


4

ASP.Netでこのような問題が発生しました。$.postPageHandlerFactoryがGET,HEAD,POST,DEBUG動詞のみに応答するように制限されているため、jQuery を実行してHTMLコンテンツを取得しようとすると、IISが内部サーバーエラーを返していました。したがって、リストに動詞「OPTIONS」を追加するか、「すべての動詞」を選択して、その制限を変更できます。

IISマネージャーでそれを変更し、Webサイトを選択してから、ハンドラーマッピングを選択し、必要に応じて* .apxファイルのPageHandlerFactoryをダブルクリックします(フレームワーク4.0の統合アプリケーションプールを使用します)。[Request Restrictions]をクリックし、[Verbs Tabn]に移動して変更を適用します。

今、私たちの$.postリクエストは期待通りに機能しています:)


2

フォームのactionURLにwwwドメインの一部が含まれているかどうかを確認しますwww。開いた元のページはなしで表示されます。

通常、正規URLに対して行われます。

私はこの記事に出くわす前に何時間も苦労し、クロスドメインのヒントを見つけました。


2

o.url = 'index.php'このファイルが存在する場合は問題なく、コンソールに成功メッセージが返されるようです。urlを使用するとエラーが返されます。http://www.google.com

投稿リクエストを行う場合、なぜ$ .postメソッドを直接使用しないのか:

$.post("test.php", { func: "getNameAndTime" },
    function(data){
        alert(data.name); // John
        console.log(data.time); //  2pm
    }, "json");

それはとても簡単です。


これについても同じことが言えます。少なくとも$ .ajax()を使用する必要があるので、少なくともエラー条件に関するデバッグ情報を取得できます。–
fitzgeraldsteele


1

これに対する解決策は:

  1. dataTypeを使用: json
  2. &callback=?あなたのURLに追加

これは、Facebook APIの呼び出しとFirefoxで機能しました。Firebugは、上記の条件のGET代わりにOPTIONS(両方とも)を使用しています。




0

オプションを追加してみてください:

dataType: "json"


2
それが機能したのに、なぜjsonがクロスドメイン要求に対して「安全」であると考えられるのですか?
Nik So

0
 function test_success(page,name,id,divname,str)
{ 
 var dropdownIndex = document.getElementById(name).selectedIndex;
 var dropdownValue = document.getElementById(name)[dropdownIndex].value;
 var params='&'+id+'='+dropdownValue+'&'+str;
 //makerequest_sp(url, params, divid1);

 $.ajax({
    url: page,
    type: "post",
    data: params,
    // callback handler that will be called on success
    success: function(response, textStatus, jqXHR){
        // log a message to the console
        document.getElementById(divname).innerHTML = response;

        var retname = 'n_district';
        var dropdownIndex = document.getElementById(retname).selectedIndex;
        var dropdownValue = document.getElementById(retname)[dropdownIndex].value;
        if(dropdownValue >0)
        {
            //alert(dropdownValue);
            document.getElementById('inputname').value = dropdownValue;
        }
        else
        {
            document.getElementById('inputname').value = "00";
        }
        return;
        url2=page2; 
        var params2 = parrams2+'&';
        makerequest_sp(url2, params2, divid2);

     }
});         
}

質問は6か月前に既に回答されています。これはどのように解決しますか?
Barmar

0

Facebook APIを使用しようとすると、同様の問題が発生しました。

Preflightedリクエストを送信しなかった唯一のcontentTypeは、単なるtext / plainのように見えました... ここの mozilla 言及されている残りのパラメーターではありません

  • なぜこれがこれを行う唯一のブラウザなのですか?
  • Facebookがプリフライトリクエストを認識して受け入れないのはなぜですか?

参考までに:前述のMozドキュメントでは、X-Loriヘッダーがプリフライト要求をトリガーする必要があることを示唆していますが、トリガーしません。


0

サーバー側でいくつかの作業を行う必要があります。サーバーサイドでPHPを使用しているようですが、.NET Webアプリケーションのソリューション は次のとおりです。jQuery.ajaxでcontent-typeを 'application / json'に設定できません

PHPスクリプトでも同じことを実行すれば動作します。簡単に言うと、最初のリクエストブラウザーは、そのようなタイプでそのようなデータを送信できるかどうかをサーバーに要求し、2番目のリクエストは適切/許可されます。


0

以下を追加してみてください:

dataType: "json",
ContentType: "application/json",
data: JSON.stringify({"method":"getStates", "program":"EXPLORE"}),  

0

別のサーバーでホストされている自分のapache solrにデータを投稿する場合、プロキシURLを使用して同様の問題を解決しました。(これは完璧な答えではないかもしれませんが、私の問題を解決します。)

このURLに従います。プロキシにMode-Rewriteを使用して、次の行をhttpd.confに追加します

 RewriteRule ^solr/(.*)$ http://ip:8983/solr$1 [P]

したがって、http:// ip:8983 / solr / *にデータをポストする代わりに、/ solrにデータをポストするだけで済みます。その後、同じオリジンでデータを投稿します。


0

私はすでにこのコードでPHPのCOR状況をうまく処理しています。

header( 'Access-Control-Allow-Origin: '.CMSConfig::ALLOW_DOMAIN );
header( 'Access-Control-Allow-Headers: '.CMSConfig::ALLOW_DOMAIN );
header( 'Access-Control-Allow-Credentials: true' );

また、ローカルでもリモートでも問題なく機能しましたが、リモートでのアップロードには適していませんでした。

apache / phpまたは私のコードで何かが発生しました。わざわざ検索する必要はありませんでした。OPTIONSをリクエストすると、corsルールを含むヘッダーが返されますが、結果は302です。したがって、私のブラウザは許容できる状況として認識しません。

@Mark McDonaldの回答に基づいて私がしたことは、ヘッダーの後にこのコードを置くだけです:

if( $_SERVER['REQUEST_METHOD'] === 'OPTIONS' )
{
    header("HTTP/1.1 202 Accepted");
    exit;
}

これで、リクエスト時にOPTIONSヘッダーと202結果が送信されます。


-1

ご承知おき下さい:

JSONPはGETリクエストメソッドのみをサポートします。

* Firefoxでリクエストを送信する:*

$.ajax({
   type: 'POST',//<<===
   contentType: 'application/json',
   url: url,
   dataType: "json"//<<=============
    ...
});

上記のリクエストはOPTIONSで送信されます(==> タイプ: 'POST')!!!!

$.ajax({
    type: 'POST',//<<===
    contentType: 'application/json',
    url: url,
    dataType: "jsonp"//<<==============
    ...
});

しかし、上記のリクエストはGETによって送信されます(==> タイプ: 'POST')!!!!

「クロスドメイン通信」のときは、注意して注意してください。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.