クロスオリジンリソースシェアリング(CORS)POSTリクエストを機能させる方法


216

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

  • 後藤ます。http://マシンA:8080これはディスプレイライブラリー
  • ライブラリが表示されます
  • ユーザーは次のコマンドを発行する「変換」リンクをクリックします-

jQuery Ajaxリクエスト

$.post('http://machineA:8081', {file_url: 'asfd'}, function(d){console.log(d)})
  • ブラウザは、次のヘッダーを含むHTTP 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
  • サーバーは次のように応答します。

応答ヘッダー-オプション(ステータス= 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ヘッダー(Access-Control-Allow-Origin:*)で応答したため、ブラウザーはPOST要求を発行する必要があります

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

リクエストヘッダー-オプション

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

応答ヘッダー-オプション(ステータス= 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(STATUS = 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

同じリクエストが一方のサイトでは機能するが、他方では機能しない理由を理解できません。誰かが私が欠けているものを指摘できるかもしれないことを願っています。ご協力いただきありがとうございます!


両方のWebサーバーが同じマシン上にある場合、CORSは必要ですか?
jdigital 2011

8
私の知る限りでは、ポートが異なるため、これはCORSリクエストです。また、OPTIONSリクエストは、ブラウザがそれをCORSリクエストとして処理していることを示しています
James

回答:


157

私はようやくこのリンクに出くわしました。「CORS POSTリクエストはプレーンなJavaScriptから機能しますが、jQueryを使用しないのはなぜですか?」とjQuery 1.5.1は

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

すべてのCORSリクエストのヘッダー。jQuery 1.5.2はこれを行いません。また、同じ質問によれば、サーバー応答ヘッダーを

Access-Control-Allow-Headers: *

応答を続行できません。応答ヘッダーに必要なヘッダーが明確に含まれていることを確認する必要があります。つまり:

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

70

リクエスト:

 $.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

3
サーバーがクロスオリジンを受け入れない場合、crossdomain = trueは問題を解決する必要はありません。dataType: "jsonp"を使用し、jsonpCallback: "response"のようなコールバックを設定することは、これを行うためのより良いアイデアです。参照:api.jquery.com/jquery.ajax
BonifatiusK

14

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":"*"
      }

**
これがお役に立てば幸いです。


これは、サーバー側で何も変更せずに機能した唯一のソリューションです... thanx miracool
Timsta

1
@ティムスタ、私の提案があなたのために働いたことに満足しています。スタックオーバーフローにも感謝しています。すてきな一日を。
Miracool

13

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

サーバーが正しく応答し、リクエストに問題がある場合は、リクエストにを追加withCredentials: trueする必要がありますxhrFields

$.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が必要です


jqueryバージョンは大丈夫ですか?設定しましたwithCredentials: trueか?関連するヘッダーがあることを確認しますか?
2017

はい、1withCredential:true , jqueryバージョン:3.2.1`。実際、郵便配達員を介して動作していますが、
Chrome

1
郵便配達員はブラウザではなく、動作が異なるため、郵便配達員にCORSの問題が発生しないはずです。サーバーからクライアントに送信される、適切で適切なヘッダーがあることを確認しましたか?繰り返します、この変更だけでは不十分です。正しいヘッダーを使用してサーバーの応答を確認する必要があります。
Dekel、

サーバーで必要な応答ヘッダーは何ですか?
Mox Shah

@MoxShahこれは完全に異なる質問であり、そこには多くのリソースがあります:)
Dekel

9

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

これを行うための最も簡単で、最も準拠し、ハッキングされていない方法は、おそらくブラウザーベースの呼び出しを行わず、クロスオリジンリクエストを処理できるプロバイダーJavaScript APIを使用することです。

たとえば、Facebook JavaScript APIやGoogle JS APIなどです。

APIプロバイダーが最新ではなく、その応答でCross Origin Resource Origin '*'ヘッダーをサポートせず、JS APIがない場合(はい、私はYahooについて話している)、3つのオプションのいずれかに悩まされています-

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

  2. 自分がコントローラーであり、クライアントと同じドメインにあるか、クロスオリジンリソースシェアリングが有効になっているAPIサーバーにリクエストを送信します。そこから、リクエストをサードパーティのAPIサーバーにプロキシできます。

  3. OAuthリクエストを作成していて、ユーザーインタラクションを処理する必要がある場合に、おそらく最も便利です。 window.open('url',"newwindowname",'_blank', 'toolbar=0,location=0,menubar=0')


4

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


6
CORSヘッダーをリクエストに手動で追加する理由はありません。ブラウザは常に、リクエストにprop CORSヘッダーを追加します。
レイニコラス2014

1
本当の課題は、サーバーが正しい応答を返すようにし、Access-Control-Allow-HeadersJQが正しいAccess-Control-Request-Headers(およびコードを介して追加したもの)を提供することです。どちらもワイルドカードにすることはできません。If-None-Matchサーバーにリストされていない場合、条件付きGETに使用するなど、プリフライトを爆破するのに必要なヘッダーは1つだけです。
escape-llc 2017年

1

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

この単純な関数は、CORS対応ページからHTTPステータス応答を非同期的に取得します。これを実行すると、GETまたはPOSTのどちらを使用しても、XMLHttpRequestを介してアクセスした場合、適切なヘッダーを持つページだけが200ステータスを返すことがわかります。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

私はまったく同じ問題を抱えていましたが、jquery ajaxは、getリクエストが正常に機能するpostリクエストでのみcorsの問題を提供しました。サーバーなどに正しいヘッダーがありました。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

これは私にとってうまくいったことの要約です:

新しい関数を定義します($.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に変換し、サーバーログに機密情報を表示する場合があります。


0

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

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

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

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

  • 代理
  • proxy_connect
  • proxy_http

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


-3

これはパーティーには少し遅れますが、私はこれに数日間苦労しています。それは可能であり、私がここで見つけた答えはどれもうまくいきませんでした。一見シンプルです。これが.ajax呼び出しです。

    <!DOCTYPE HTML>
    <html>
    <head>
    <body>
     <title>Javascript Test</title>
     <script src="http://code.jquery.com/jquery-latest.min.js"></script>
     <script type="text/javascript">
     $(document).domain = 'XXX.com';
     $(document).ready(function () {
     $.ajax({
        xhrFields: {cors: false},
        type: "GET",
        url: "http://XXXX.com/test.php?email='steve@XXX.com'",
        success: function (data) {
           alert(data);
        },
        error: function (x, y, z) {
           alert(x.responseText + " :EEE: " + x.status);
        }
    });
    });
    </script> 
    </body>
    </html>

サーバー側のphpは次のとおりです。

    <html>
    <head>
     <title>PHP Test</title>
     </head>
    <body>
      <?php
      header('Origin: xxx.com');
      header('Access-Control-Allow-Origin:*');
      $servername = "sqlxxx";
      $username = "xxxx";
      $password = "sss";
      $conn = new mysqli($servername, $username, $password);
      if ($conn->connect_error) {
        die( "Connection failed: " . $conn->connect_error);
      }
      $sql = "SELECT email, status, userdata  FROM msi.usersLive";
      $result = $conn->query($sql);
      if ($result->num_rows > 0) {
      while($row = $result->fetch_assoc()) {
        echo $row["email"] . ":" . $row["status"] . ":" . $row["userdata"] .  "<br>";
      }
    } else {
      echo "{ }";
    }
    $conn->close();
    ?>
    </body>


1
価値があるのは、Originヘッダーが要求ヘッダーであり、応答ヘッダーではないことです。あなたのPHPスクリプトはそれを設定するべきではありません。
麺類

ふん。これで私の期待が高まり、コードでAJAXの「GET」を作成しているのを見たとき、OPが「GET」を使用して回避しようとしていることを明確に示し、「POST」を使用したかったので、それらを打ち消しました。
Steve Sauder 2017年

CORSヘッダーは、関係する動詞に関係なく同じように機能します。$.ajax()正しく構成されたサーバーに対して、すべての動詞を呼び出すことができます。一番難しいのはAccess-Control-Request-Headers正しいことですが、それでもそれほど難しくはありません。以前のポスターで述べたように、これはワイルドカードではなく、ヘッダーのホワイトリストでなければなりません。
escape-llc 2017年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.