Kaynaklar arası kaynak paylaşımı (CORS) yayın isteği nasıl çalışır


216

Yerel LAN (machineA) üzerinde iki web sunucusu olan bir makinem var. Birincisi, XBMC'deki (8080 bağlantı noktasında) yerleşik olanıdır ve kütüphanemizi görüntüler. İkinci sunucu, talep üzerine bir dosya dönüştürmeyi tetiklemek için kullandığım bir CherryPy python betiğidir (bağlantı noktası 8081). Dosya dönüştürme XBMC sunucusundan sunulan sayfadan bir AJAX POST isteği ile tetiklenir.

  • Goto http: // MachineA: 8080 hangi görüntüler kütüphane
  • Kütüphane görüntülenir
  • Kullanıcı aşağıdaki komutu veren 'dönüştür' bağlantısını tıklar -

jQuery Ajax İsteği

$.post('http://machineA:8081', {file_url: 'asfd'}, function(d){console.log(d)})
  • Tarayıcı aşağıdaki başlıklarla bir HTTP SEÇENEKLERİ isteği gönderir;

Talep Başlığı - SEÇENEKLER

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
  • Sunucu aşağıdakileri yanıtlar;

Yanıt Başlığı - SEÇENEKLER (DURUM = 200 Tamam)

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
  • Daha sonra konuşma durur. Teorik olarak, sunucu doğru (?) CORS başlıklarıyla (Access-Control-Allow-Origin: *) yanıt verirken, bir POST isteği yayınlamalıdır.

Sorun giderme için http://jquery.com adresinden de aynı $ .post komutunu verdim . Burada güdük olduğum yer, jquery.com, posta isteği çalışır, bir POST tarafından sonra bir SEÇENEKLER isteği gönderilir. Bu işlemin başlıkları aşağıdadır;

Talep Başlığı - SEÇENEKLER

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

Yanıt Başlığı - SEÇENEKLER (DURUM = 200 Tamam)

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

Başlık İsteği - 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

Yanıt Başlığı - 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

Aynı isteğin neden bir siteden işe yaradığını, diğerinin işe yaramadığını anlayamıyorum. Birisinin eksik olduğumu gösterebileceğini umuyorum. Yardımınız için teşekkürler!


Her iki web sunucusu aynı makinede ise CORS'ye ihtiyaç var mı?
jdigital

8
Bildiğim kadarıyla, farklı liman nedeniyle bir CORS isteğidir. Ayrıca, SEÇENEKLER isteği, tarayıcının bir CORS isteği olarak davrandığını gösterir
James

Yanıtlar:


157

Sonunda bu bağlantı üzerine tökezledi " Bir CORS POST isteği düz javascript çalışır, ama neden jQuery ile değil? " JQuery 1.5.1

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

Tüm CORS isteklerine başlık. jQuery 1.5.2 bunu yapmaz. Ayrıca, aynı soruya göre, bir sunucu yanıt başlığı ayarlamak

Access-Control-Allow-Headers: *

yanıtın devam etmesine izin vermez. Yanıt başlığının özellikle gerekli başlıkları içerdiğinden emin olmanız gerekir. yani:

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

70

İSTEK:

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

TEPKİ:

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

return response

3
sunucu çapraz menşei kabul etmezse, crossdomain = true sorunu çözmek zorunda değildir. dataType: "jsonp" kullanarak ve geri aramayı jsonpCallback gibi ayarlamak: "response" bunu yapmak için daha iyi bir fikir olacaktır. Ayrıca bakınız: api.jquery.com/jquery.ajax
BonifatiusK

14

Google uzaklık matrisi API'sini kullanırken kendi başlığımı Jquery ajax ile istek başlığımı ayarlayarak çözdüm. aşağıya bir göz atın.

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

      });

Ayarlara neler eklediğimi not edin
**

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

**
Umarım bu yardımcı olur.


Bu sunucu tarafında bir şey değiştirmeden bizim için çalışan tek çözüm ... thanx miracool
Timsta

1
@Timsta, önerimin senin için çalıştığı için mutluyum. Ayrıca taşma yığını için minnettarım. İyi günler.
Miracool

13

Çözümü bulmak için bana biraz zaman ayırdı.

Durumda sunucu doğru yanıt ve istek sorunu, eklemek gerekir olduğunu withCredentials: trueiçin xhrFieldsistekte:

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

Not: jQuery> = 1.5.1 gereklidir


jquery sürümü tamam mı? ayarladın withCredentials: truemı? ilgili başlıklara sahip olduğunuzdan emin misiniz?
Dekel

Evet, 1withCredential: gerçek , jquery sürümü: 3.2.1`. Aslında postacı aracılığıyla çalışıyor, ancak krom tarayıcıdan geçmiyor
Mox Shah

1
Postacıların CORS sorunları olmaması gerektiğinden neredeyse eminim çünkü tarayıcı değil ve davranışı farklı. Sunucudan istemciye doğru ve alakalı başlıkların gönderildiğinden emin misiniz? Tekrar - bu değişikliğin yeterli olmadığını unutmayın . Sunucunun doğru başlıklarla yanıt verdiğinden emin olmanız gerekir .
Dekel

Sunucuda gereken yanıt başlığının ne olduğunu söyleyebilir misiniz?
Mox Shah

@MoxShah bu tamamen farklı bir soru ve orada çok fazla kaynak var :)
Dekel

9

Birkaç hafta boyunca bu sorunla mücadele ettim.

Bunu yapmanın en kolay, en uyumlu ve hileli olmayan yolu, muhtemelen tarayıcı tabanlı arama yapmayan ve Cross Origin isteklerini işleyebilen bir sağlayıcı JavaScript API'sini kullanmaktır.

Örneğin Facebook JavaScript API'sı ve Google JS API'sı.

API sağlayıcınızın güncel olmaması ve yanıtında Cross Origin Resource Origin '*' başlığını desteklememesi ve bir JS api (Evet, Yahoo'dan bahsediyorum) olmaması durumunda, üç seçenekten birini kullanabilirsiniz.

  1. URL'nize yanıtınızı işleyebileceğiniz bir geri arama işlevi ekleyen isteklerinizde jsonp kullanma. Dikkat edin, bu istek URL'sini değiştirir, böylece API sunucunuzun URL'nin sonunda? Callback = parametresini işleyecek şekilde donatılması gerekir.

  2. İsteği, sizin tarafınızdan denetleyici olan ve istemciyle aynı etki alanında olan veya isteği 3. taraf API sunucusuna proxy gönderebileceğiniz Çapraz Kaynak Kaynağı Paylaşımı etkinleştirilmiş olan API sunucunuza gönderin.

  3. Muhtemelen en çok OAuth istekleri yaptığınız ve kullanıcı etkileşimi Haha! window.open('url',"newwindowname",'_blank', 'toolbar=0,location=0,menubar=0')


4

Bunu Laravel ile birlikte kullanmak sorunumu çözdü. Bu üstbilgiyi jquery isteğinize ekleyin Access-Control-Request-Headers: x-requested-withve sunucu tarafı yanıtınızda bu üstbilginin ayarlandığından emin olun Access-Control-Allow-Headers: *.


6
CORS başlıklarını isteğe manuel olarak eklemek için hiçbir neden yoktur. Tarayıcı her zaman prop CORS başlıklarını sizin için isteğe ekleyecektir.
Ray Nicholus

1
Asıl zorluk, sunucunun, her ikisi de joker karakterler olabilen doğru Access-Control-Allow-Headersve JQ sağlayarak Access-Control-Request-Headers(artı kod yoluyla eklediğiniz) yanıt vermesini sağlamaktır . If-None-Matchsunucu önceden listelenmemişse , örneğin bir koşullu GET için kullanmak gibi uçuş öncesi havaya uçurmak için yalnızca bir "kötü" başlık gerekir.
escape-llc

1

Bazı nedenlerden dolayı, GET istekleriyle ilgili bir soru bununla birleştirildi, bu yüzden burada yanıtlayacağım.

Bu basit işlev, CORS etkin bir sayfadan eşzamansız olarak bir HTTP durum yanıtı alır. Çalıştırırsanız, yalnızca uygun başlıklara sahip bir sayfanın XMLHttpRequest üzerinden erişilirse (GET veya POST kullanılsa da) 200 durumu döndürdüğünü görürsünüz. Sadece json nesnesine ihtiyacınız varsa, JSONP kullanmak dışında istemci tarafında hiçbir şey yapılamaz.

XmlHttpRequestObject nesnesinde tutulan verileri almak için aşağıdakiler kolayca değiştirilebilir:

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

Ben jquery ajax sadece bana istekleri iyi çalıştı sonrası istekleri üzerinde cors sorunları verdi tam olarak aynı sorunu vardı - hiçbir sonuç ile yukarıdaki her şeyi yorgun. Sunucum vb doğru başlıkları vardı. Jquery yerine XMLHTTPRequest kullanmak için değiştirme sorunumu hemen düzeltildi. Hangi jquery sürümünü kullandığım önemli değil, düzeltmedi. Geriye doğru tarayıcı uyumluluğuna ihtiyacınız yoksa Getir de sorunsuz çalışır.

        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)

Umarım bu aynı sorunları olan herkese yardımcı olur.


1

Bu benim için işe yarayan şeyin bir özetidir:

Yeni bir işlev tanımlayın ( $.ajaxbasitleştirmek için sarılmış ):

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

Kullanımı:

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

Ayrıca çalışır .done, .failvb:

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

Sunucu tarafı (example.com'un barındırıldığı bu durumda), bu başlıkları ayarlayın (PHP'de bazı örnek kodlar eklendi):

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'den gerçekten etki alanları arası POST yapmanın tek yolu budur.

JSONP, POST'u sunucu günlüklerinde hassas bilgiler görüntüleyebilen GET'e dönüştürür.


0

Bazı nedenlerden dolayı üstbilgileri eklemeye veya denetim ilkesini ayarlamaya çalışırken hala hiçbir yerde almıyorsanız apache ProxyPass kullanmayı düşünebilirsiniz…

Örneğin <VirtualHost>, SSL kullanan birinde şu iki yönergeyi ekleyin:

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

Aşağıdaki apache modüllerinin yüklendiğinden emin olun (a2enmod kullanarak yükleyin):

  • vekil
  • proxy_connect
  • proxy_http

Açıkçası, apache proxy kullanmak için AJAX istekleri url değiştirmek zorunda kalacak ...


-3

Bu partiye biraz geç kaldı, ama birkaç gündür bununla mücadele ediyorum. Bu mümkün ve burada bulduğum cevapların hiçbiri işe yaramadı. Aldatıcı derecede basit. İşte .ajax çağrısı:

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

İşte sunucu tarafında 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
Değeri ne olursa olsun, Origin başlığı bir yanıt başlığı değil, bir istek başlığıdır. Php betiğiniz ayarlamamalıdır.
Erişte

Hmmph. Bu benim umutlarımı aldı ve daha sonra kodunuzda bir AJAX "GET" yaptığınızı görünce onları kesik, OP açıkça "GET" kullanarak KAÇININ ve "POST" kullanmak istediğini açıkça söyledi.
Steve Sauder

CORS başlıkları, söz konusu fiilden bağımsız olarak aynı şekilde çalışır. Tüm fiilleri $.ajax()doğru yapılandırılmış bir sunucuya karşı çağırabiliriz . En zor kısım Access-Control-Request-Headersdoğru olanı bulmak , ama bu bile çok zor değil. Önceki posterlerde belirtildiği gibi, bu bir joker karakter değil, başlıkların beyaz listesi olmalıdır.
escape-llc
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.