Cara mendapatkan permintaan pos berbagi sumber daya lintas (CORS) bekerja

216

Saya memiliki mesin di lan lokal saya (machineA) yang memiliki dua server web. Yang pertama adalah yang built-in di XBMC (pada port 8080) dan menampilkan perpustakaan kami. Server kedua adalah skrip python CherryPy (port 8081) yang saya gunakan untuk memicu konversi file sesuai permintaan. Konversi file dipicu oleh permintaan POST AJAX dari halaman yang disajikan dari server XBMC.

  • Goto http: // machineA: 8080 yang menampilkan perpustakaan
  • Perpustakaan ditampilkan
  • Pengguna mengklik tautan 'convert' yang mengeluarkan perintah berikut -

Permintaan jQuery Ajax

$.post('http://machineA:8081', {file_url: 'asfd'}, function(d){console.log(d)})
  • Browser mengeluarkan permintaan HTTP OPTIONS dengan header berikut;

Header Permintaan - OPSI

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
  • Server merespons dengan yang berikut;

Header Respons - PILIHAN (STATUS = 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
  • Percakapan kemudian berhenti. Browser, secara teori, harus mengeluarkan permintaan POST ketika server merespons dengan header CORS yang benar (? Access-Control-Allow-Origin: *)

Untuk pemecahan masalah, saya juga telah mengeluarkan perintah $ .post yang sama dari http://jquery.com . Di sinilah saya bingung, dari jquery.com, permintaan posting berfungsi, permintaan OPSI dikirim diikuti oleh POST. Tajuk dari transaksi ini di bawah;

Header Permintaan - OPSI

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

Header Respons - PILIHAN (STATUS = 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

Header Permintaan - 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

Header Respons - 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

Saya tidak tahu mengapa permintaan yang sama akan berfungsi dari satu situs, tetapi tidak yang lain. Saya berharap seseorang mungkin bisa menunjukkan apa yang saya lewatkan. Terima kasih atas bantuan Anda!

James
sumber
Apakah CORS diperlukan jika kedua server web berada pada mesin yang sama?
jdigital
8
Sepengetahuan saya, ini adalah permintaan CORS karena port yang berbeda. Selain itu, permintaan PILIHAN menunjukkan bahwa peramban memperlakukannya sebagai permintaan CORS
James

Jawaban:

157

Saya akhirnya menemukan tautan ini " Permintaan CORS POST berfungsi dari javascript biasa, tetapi mengapa tidak dengan jQuery? " Yang mencatat bahwa jQuery 1.5.1 menambahkan

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

tajuk ke semua permintaan CORS. jQuery 1.5.2 tidak melakukan ini. Juga, sesuai dengan pertanyaan yang sama, mengatur header respons server

Access-Control-Allow-Headers: *

tidak memungkinkan tanggapan untuk melanjutkan. Anda perlu memastikan tajuk respons secara khusus menyertakan tajuk yang diperlukan. yaitu:

Access-Control-Allow-Headers: x-requested-with 
James
sumber
70

PERMINTAAN:

 $.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");
            }
        });

TANGGAPAN:

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

return response
Hassan Zaheer
sumber
3
jika server tidak menerima asal silang, crossdomain = true tidak harus menyelesaikan masalah. menggunakan dataType: "jsonp" dan mengatur panggilan balik seperti jsonpCallback: "response" akan menjadi ide yang lebih baik untuk melakukan ini. Lihat juga: api.jquery.com/jquery.ajax
BonifatiusK
14

Saya memecahkan masalah saya sendiri ketika menggunakan google distance matrix API dengan mengatur header permintaan saya dengan Jquery ajax. lihat di bawah.

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);

      });

Perhatikan apa yang saya tambahkan di pengaturan
**

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

**
Saya harap ini membantu.

Miracool
sumber
ini adalah satu-satunya solusi yang bekerja untuk kita tanpa mengubah apa pun di sisi server ... thanx miracool
Timsta
1
@Timsta, saya senang saran saya berhasil untuk Anda. Bersyukur juga untuk stack overflow. Semoga hari mu menyenangkan.
Miracool
13

Butuh waktu untuk mencari solusinya.

Jika respons server Anda benar dan permintaan adalah masalahnya, Anda harus menambahkan withCredentials: trueke xhrFieldsdalam permintaan:

$.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
    }
});

Catatan: jQuery> = 1.5.1 diperlukan

Dekel
sumber
versi jquery ok? Apakah Anda mengatur withCredentials: true? Anda yakin memiliki tajuk yang relevan?
Dekel
Ya, 1withCredential: true , jquery versi: 3.2.1`. Bahkan ia bekerja melalui tukang pos, tetapi tidak melewati browser chrome
Mox Shah
1
Saya hampir yakin tukang pos tidak boleh memiliki masalah CORS karena itu bukan browser dan perilakunya berbeda. Anda yakin Anda memiliki tajuk yang benar dan relevan yang dikirim dari server ke klien? Sekali lagi - perhatikan bahwa perubahan ini tidak cukup. Anda perlu memastikan respons server dengan tajuk yang benar .
Dekel
Bisakah Anda memberi tahu saya apa yang diperlukan header respons di server?
Mox Shah
@MoxShah ini pertanyaan yang sangat berbeda dan ada banyak sumber di sana :)
Dekel
9

Yah saya kesulitan dengan masalah ini selama beberapa minggu.

Cara termudah, paling patuh, dan tidak meretas untuk melakukan ini adalah mungkin menggunakan penyedia API JavaScript yang tidak membuat panggilan berbasis browser dan dapat menangani permintaan Cross Origin.

Misalnya Facebook JavaScript API dan Google JS API.

Seandainya penyedia API Anda tidak mutakhir dan tidak mendukung tajuk Cross Origin Resource Origin '*' dalam tanggapannya dan tidak memiliki JS api (Ya saya berbicara tentang Anda Yahoo), Anda dikejutkan dengan salah satu dari tiga opsi-

  1. Menggunakan jsonp dalam permintaan Anda yang menambahkan fungsi panggilan balik ke URL tempat Anda dapat menangani respons Anda. Peringatan ini akan mengubah URL permintaan sehingga server API Anda harus dilengkapi untuk menangani? Callback = di akhir URL.

  2. Kirim permintaan ke server API Anda yang dikontrol oleh Anda dan berada di domain yang sama dengan klien atau mengaktifkan Cross Origin Resource Sharing dari mana Anda dapat mem-proxy permintaan tersebut ke server API pihak ke-3.

  3. Mungkin paling berguna dalam kasus di mana Anda membuat permintaan OAuth dan perlu menangani interaksi pengguna Haha! window.open('url',"newwindowname",'_blank', 'toolbar=0,location=0,menubar=0')

Pritam Roy
sumber
4

Menggunakan ini dalam kombinasi dengan Laravel memecahkan masalah saya. Cukup tambahkan tajuk ini ke permintaan jquery Anda Access-Control-Request-Headers: x-requested-withdan pastikan bahwa respons sisi server Anda memiliki set tajuk ini Access-Control-Allow-Headers: *.

MK
sumber
6
Tidak ada alasan untuk menambahkan header CORS ke permintaan secara manual. Browser akan selalu menambahkan tajuk prop CORS ke permintaan untuk Anda.
Ray Nicholus
1
Tantangan sebenarnya adalah mendapatkan server untuk membalas dengan Access-Control-Allow-HeadersJQ yang benar dan menyediakan yang benar Access-Control-Request-Headers(ditambah setiap Anda menambahkan melalui kode) yang keduanya tidak dapat wildcard. hanya diperlukan satu tajuk "buruk" untuk meledakkan pra-penerbangan, misalnya menggunakan If-None-Matchuntuk GET bersyarat, jika server tidak memiliki yang terdaftar.
escape-llc
1

Untuk beberapa alasan, pertanyaan tentang permintaan GET digabung dengan yang ini, jadi saya akan menjawabnya di sini.

Fungsi sederhana ini secara asinkron akan mendapatkan balasan status HTTP dari halaman yang mendukung CORS. Jika Anda menjalankannya, Anda akan melihat bahwa hanya halaman dengan tajuk yang tepat mengembalikan status 200 jika diakses melalui XMLHttpRequest - apakah GET atau POST digunakan. Tidak ada yang dapat dilakukan di sisi klien untuk menyiasati hal ini kecuali mungkin menggunakan JSONP jika Anda hanya memerlukan objek json.

Berikut ini dapat dengan mudah dimodifikasi untuk mendapatkan data yang disimpan di objek 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>

Victor Stoddard
sumber
1

Saya memiliki masalah yang sama persis di mana jquery ajax hanya memberi saya masalah kors pada permintaan pos di mana mendapatkan permintaan bekerja dengan baik - saya lelah semuanya di atas tanpa hasil. Saya memiliki header yang benar di server saya, dll. Mengubah untuk menggunakan XMLHTTPRequest alih-alih jquery segera memperbaiki masalah saya. Tidak peduli versi jquery yang saya gunakan tidak memperbaikinya. Ambil juga berfungsi tanpa masalah jika Anda tidak memerlukan kompatibilitas browser mundur.

        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)

Semoga ini bisa membantu orang lain dengan masalah yang sama.

ozzieisaacs
sumber
1

Ini adalah ringkasan dari apa yang berhasil untuk saya:

Tentukan fungsi baru (dibungkus $.ajaxuntuk mempermudah):

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({}) 
    }
  });
}

Pemakaian:

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

Juga bekerja dengan .done, .fail, dll:

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

Sisi server (dalam kasus ini di mana example.com di-host), setel tajuk ini (tambahkan beberapa kode sampel dalam 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);

Ini adalah satu-satunya cara yang saya tahu untuk benar-benar POST cross-domain dari JS.

JSONP mengubah POST menjadi GET yang dapat menampilkan informasi sensitif pada log server.

lepe
sumber
0

Jika karena alasan tertentu saat mencoba menambahkan header atau menetapkan kebijakan kontrol, Anda masih belum menemukan tempat yang dapat Anda pertimbangkan untuk menggunakan apache ProxyPass…

Misalnya dalam satu <VirtualHost>yang menggunakan SSL tambahkan dua arahan berikut:

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

Pastikan modul apache berikut dimuat (muat menggunakan a2enmod):

  • proksi
  • proxy_connect
  • proxy_http

Jelas Anda harus mengubah url permintaan AJAX Anda untuk menggunakan proxy apache ...

llange
sumber
-3

Ini agak terlambat ke pesta, tetapi saya telah berjuang dengan ini selama beberapa hari. Itu mungkin dan tidak ada jawaban yang saya temukan di sini yang berfungsi. Ini tampak sederhana. Inilah panggilan .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='[email protected]'",
        success: function (data) {
           alert(data);
        },
        error: function (x, y, z) {
           alert(x.responseText + " :EEE: " + x.status);
        }
    });
    });
    </script> 
    </body>
    </html>

Inilah php di sisi server:

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

Steve Johnson
sumber
1
Untuk apa nilainya, header Asal adalah header permintaan, bukan header respons. Script php Anda seharusnya tidak mengaturnya.
Mie
Hmmh. Ini menambah harapan saya dan kemudian menghancurkan mereka ketika saya melihat Anda membuat "GET" AJAX dalam kode Anda, ketika OP dengan jelas mengatakan ia mencoba MENGHINDARI menggunakan "GET" dan ingin menggunakan "POST".
Steve Sauder
Header CORS bekerja sama terlepas dari kata kerja yang terlibat. Kami dapat menjalankan semua kata kerja melalui $.ajax()server yang dikonfigurasi dengan benar. Bagian tersulit adalah mendapatkan yang Access-Control-Request-Headersbenar, tetapi itu pun tidak terlalu sulit. Seperti dicatat oleh poster sebelumnya, ini tidak boleh wildcard tapi daftar putih header.
escape-llc