web-dev-qa-db-ja.com

クロスオリジンリソース共有(CORS)ポストリクエストを機能させる方法

私は自分のローカルLAN(machineA)に2台のWebサーバーを持つマシンを持っています。 1つ目はXBMCに組み込まれたもの(ポート8080)で、私たちのライブラリを表示します。 2番目のサーバーは、CherryPy pythonスクリプト(ポート8081)です。これは、オンデマンドでファイル変換を起動するために使用しています。ファイル変換は、XBMCサーバーから提供されたページからのAJAX POST要求によって開始されます。

  • 後藤 http:// machineA:8080 図書館を表示する
  • 図書館が表示されます
  • ユーザーが次のコマンドを発行する 'convert'リンクをクリック -

jQuery Ajaxリクエスト

$.post('http://machineA:8081', {file_url: 'asfd'}, function(d){console.log(d)})
  • ブラウザは以下のヘッダを含むHTTP OPTIONSリクエストを発行します。

リクエストヘッダ - OPTIONS

Host: machineA:8081
User-Agent: ... Firefox/4.01
Accept: 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
Keep-Alive: 115
Connection: keep-alive
Origin: http://machineA:8080
Access-Control-Request-Method: POST
Access-Control-Request-Headers: x-requested-with
  • サーバーは次のように応答します。

レスポンスヘッダ - OPTIONS(ステータス= 200 OK)

Content-Length: 0
Access-Control-Allow-Headers: *
Access-Control-Max-Age: 1728000
Server: CherryPy/3.2.0
Date: Thu, 21 Apr 2011 22:40:29 GMT
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: POST, GET, OPTIONS
Content-Type: text/html;charset=ISO-8859-1
  • 会話はその後停止します。ブラウザは、理論的には、サーバーが正しい(?)CORSヘッダーで応答したときにPOST要求を発行する必要があります(Access-Control-Allow-Origin:*)。

トラブルシューティングのために、私は http://jquery.com から同じ$ .postコマンドを発行しました。これが私が困っているところです、jquery.comから、投稿要求が機能し、OPTIONS要求がPOSTの後に送信されます。このトランザクションのヘッダは以下の通りです。

リクエストヘッダ - OPTIONS

Host: machineA:8081
User-Agent: ... Firefox/4.01
Accept: 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
Keep-Alive: 115
Connection: keep-alive
Origin: http://jquery.com
Access-Control-Request-Method: POST

レスポンスヘッダ - OPTIONS(ステータス= 200 OK)

Content-Length: 0
Access-Control-Allow-Headers: *
Access-Control-Max-Age: 1728000
Server: CherryPy/3.2.0
Date: Thu, 21 Apr 2011 22:37:59 GMT
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: POST, GET, OPTIONS
Content-Type: text/html;charset=ISO-8859-1

リクエストヘッダー - POST

Host: machineA:8081
User-Agent: ... Firefox/4.01
Accept: */*
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
Keep-Alive: 115
Connection: keep-alive
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
Referer: http://jquery.com/
Content-Length: 12
Origin: http://jquery.com
Pragma: no-cache
Cache-Control: no-cache

応答ヘッダー - POST(ステータス= 200 OK)

Content-Length: 32
Access-Control-Allow-Headers: *
Access-Control-Max-Age: 1728000
Server: CherryPy/3.2.0
Date: Thu, 21 Apr 2011 22:37:59 GMT
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: POST, GET, OPTIONS
Content-Type: application/json

同じ要求が一方のサイトから機能するのに、もう一方のサイトから機能しない理由はわかりません。誰かが私が行方不明になっているものを指摘できるかもしれないことを望みます。ご協力いただきありがとうございます!

186
James

私はついにこのリンク " CORS POST要求は普通のjavascriptからうまくいくが、なぜjQueryでしないのですか? "に出会いました。

 Access-Control-Request-Headers: x-requested-with

すべてのCORS要求へのヘッダー。 jQuery 1.5.2はこれを行いません。また、同じ質問に従って、次のようにサーバー応答ヘッダーを設定します。

Access-Control-Allow-Headers: *

応答を続行できません。応答ヘッダーには、必ず必須ヘッダーが含まれるようにする必要があります。すなわち:

Access-Control-Allow-Headers: x-requested-with 
140
James

要求:

 $.ajax({
            url: "http://localhost:8079/students/add/",
            type: "POST",
            crossDomain: true,
            data: JSON.stringify(somejson),
            dataType: "json",
            success: function (response) {
                var resp = JSON.parse(response)
                alert(resp.status);
            },
            error: function (xhr, status) {
                alert("error");
            }
        });

応答:

response = HttpResponse(json.dumps('{"status" : "success"}'))
response.__setitem__("Content-type", "application/json")
response.__setitem__("Access-Control-Allow-Origin", "*")

return response
60
Hassan Zaheer

解決策を見つけるのにしばらく時間がかかりました。

サーバーが正しく応答してリクエストが問題になっている場合は、リクエストのxhrFieldswithCredentials: trueを追加してください。

$.ajax({
    url: url,
    type: method,
    // This is the important part
    xhrFields: {
        withCredentials: true
    },
    // This is the important part
    data: data,
    success: function (response) {
        // handle the response
    },
    error: function (xhr, status) {
        // handle errors
    }
});

注:jQuery> = 1.5.1は 必須 です。

12
Dekel

私は数週間この問題に苦労しました。

これを行うための最も簡単で、最も準拠性が高く、ハッキングの少ない方法は、おそらくブラウザベースの呼び出しを行わず、Cross Originの要求を処理できるプロバイダのJavaScript APIを使用することです。

例えば。 Facebook JavaScript APIとGoogle JS API。

あなたのAPIプロバイダが最新ではなく、その応答でCross Origin Resource Originの '*'ヘッダをサポートしておらず、JS APIを持っていない場合(はい、私はあなたのことを話しています)

  1. リクエストにjsonpを使用すると、URLにコールバック関数が追加され、そこでレスポンスを処理できます。警告これはリクエストURLを変更するため、APIサーバーはURLの最後に?callback =を処理するように装備されている必要があります。

  2. 自分で管理しているクライアントと同じドメインにあるか、Cross Origin Resource Sharingが有効になっているAPIサーバーにリクエストを送信し、そこからリクエストをサードパーティAPIサーバーにプロキシできます。

  3. あなたがOAuthリクエストをしていて、ユーザーとの対話を処理する必要がある場合におそらく最も有用です。 window.open('url',"newwindowname",'_blank', 'toolbar=0,location=0,menubar=0')

9
Pritam Roy

Jquery ajaxを使ってリクエストヘッダーを設定することで、Googleの距離行列APIを使用する際の問題を解決しました。以下を見てください。

var settings = {
          'cache': false,
          'dataType': "jsonp",
          "async": true,
          "crossDomain": true,
          "url": "https://maps.googleapis.com/maps/api/distancematrix/json?units=metric&origins=place_id:"+me.originPlaceId+"&destinations=place_id:"+me.destinationPlaceId+"&region=ng&units=metric&key=mykey",
          "method": "GET",
          "headers": {
              "accept": "application/json",
              "Access-Control-Allow-Origin":"*"
          }
      }

      $.ajax(settings).done(function (response) {
          console.log(response);

      });

私は設定で追加したことに注意してください
**

"headers": {
          "accept": "application/json",
          "Access-Control-Allow-Origin":"*"
      }

**
これが役に立つことを願っています。

4
Miracool

これをLaravelと組み合わせて使用​​すると、問題が解決しました。このヘッダをjqueryリクエストAccess-Control-Request-Headers: x-requested-withに追加して、サーバサイドレスポンスにこのヘッダセットAccess-Control-Allow-Headers: *があることを確認してください。

4
M K

何らかの理由で、GETリクエストに関する質問がこの質問とマージされたので、ここで回答します。

この単純な関数は、CORS対応ページからHTTPステータス応答を非同期的に取得します。実行すると、XMLHttpRequestを介してアクセスした場合、適切なヘッダーを持つページのみが200のステータスを返します(GETまたはPOSTのどちらを使用するか)。 jsonオブジェクトが必要な場合はおそらくJSONPを使用することを除いて、これを回避するためにクライアント側では何もできません。

以下は、xmlHttpRequestObjectオブジェクトに保持されているデータを取得するように簡単に変更できます。

function checkCorsSource(source) {
  var xmlHttpRequestObject;
  if (window.XMLHttpRequest) {
    xmlHttpRequestObject = new XMLHttpRequest();
    if (xmlHttpRequestObject != null) {
      var sUrl = "";
      if (source == "google") {
        var sUrl = "https://www.google.com";
      } else {
        var sUrl = "https://httpbin.org/get";
      }
      document.getElementById("txt1").innerHTML = "Request Sent...";
      xmlHttpRequestObject.open("GET", sUrl, true);
      xmlHttpRequestObject.onreadystatechange = function() {
        if (xmlHttpRequestObject.readyState == 4 && xmlHttpRequestObject.status == 200) {
          document.getElementById("txt1").innerHTML = "200 Response received!";
        } else {
          document.getElementById("txt1").innerHTML = "200 Response failed!";
        }
      }
      xmlHttpRequestObject.send();
    } else {
      window.alert("Error creating XmlHttpRequest object. Client is not CORS enabled");
    }
  }
}
<html>
<head>
  <title>Check if page is cors</title>
</head>
<body>
  <p>A CORS-enabled source has one of the following HTTP headers:</p>
  <ul>
    <li>Access-Control-Allow-Headers: *</li>
    <li>Access-Control-Allow-Headers: x-requested-with</li>
  </ul>
  <p>Click a button to see if the page allows CORS</p>
  <form name="form1" action="" method="get">
    <input type="button" name="btn1" value="Check Google Page" onClick="checkCorsSource('google')">
    <input type="button" name="btn1" value="Check Cors Page" onClick="checkCorsSource('cors')">
  </form>
  <p id="txt1" />
</body>
</html>
1
Victor Stoddard

私はjquery ajaxがgetリクエストがうまく動くようなpostリクエストの問題を私に与えたのと全く同じ問題を抱えていた - 私は結果なしで上記のすべてを疲れさせた。私は自分のサーバーなどに正しいヘッダを持っていました。jqueryの代わりにXMLHTTPRequestを使うように切り替えて、私の問題をすぐに直しました。どのバージョンのjqueryを使用しても修正されませんでした。ブラウザの後方互換性が必要ない場合は、Fetchも問題なく動作します。

        var xhr = new XMLHttpRequest()
        xhr.open('POST', 'https://mywebsite.com', true)
        xhr.withCredentials = true
        xhr.onreadystatechange = function() {
          if (xhr.readyState === 2) {// do something}
        }
        xhr.setRequestHeader('Content-Type', 'application/json')
        xhr.send(json)

うまくいけば、これは同じ問題を抱えている誰にでも役立つ。

1
ozzieisaacs

これは私のために働いたことの要約です:

新しい関数を定義します(簡単にするために$.ajaxをラップしました)。

jQuery.postCORS = function(url, data, func) {
  if(func == undefined) func = function(){};
  return $.ajax({
    type: 'POST', 
    url: url, 
    data: data, 
    dataType: 'json', 
    contentType: 'application/x-www-form-urlencoded', 
    xhrFields: { withCredentials: true }, 
    success: function(res) { func(res) }, 
    error: function() { 
            func({}) 
    }
  });
}

使用法:

$.postCORS("https://example.com/service.json",{ x : 1 },function(obj){
      if(obj.ok) {
           ...
      }
});

.done.failなどでも動作します。

$.postCORS("https://example.com/service.json",{ x : 1 }).done(function(obj){
      if(obj.ok) {
           ...
      }
}).fail(function(){
    alert("Error!");
});

サーバー側(この場合、example.comがホストされている)で、これらのヘッダーを設定します(PHPにサンプルコードを追加しました)。

header('Access-Control-Allow-Origin: https://not-example.com');
header('Access-Control-Allow-Credentials: true');
header('Access-Control-Max-Age: 604800');
header("Content-type: application/json");
$array = array("ok" => $_POST["x"]);
echo json_encode($array);

これが私がJSからPOSTクロスドメインを本当に知っている唯一の方法です。

JSONPはPOSTをGETに変換します。これにより、サーバーログに機密情報が表示される場合があります。

1
lepe

何らかの理由でヘッダを追加したり制御ポリシーを設定しようとしているときにまだどこにも行かない場合は、Apache ProxyPassの使用を検討してください。

たとえば、SSLを使用する1つの<VirtualHost>に、次の2つのディレクティブを追加します。

SSLProxyEngine On
ProxyPass /oauth https://remote.tld/oauth

次のApacheモジュールがロードされていることを確認してください(a2enmodを使用してロードしてください)。

  • 代理人
  • proxy_connect
  • proxy_http

Apacheプロキシを使用するには、明らかにAJAXリクエストのURLを変更する必要があります…

0
llange