Bir CORS POST isteği düz JavaScript'ten çalışır, ancak neden jQuery ile çalışmasın?


88

Bir Cross Origin gönderi talebinde bulunmaya çalışıyorum ve bunu JavaScriptşu şekilde düz bir şekilde çalıştırdım :

var request = new XMLHttpRequest();
var params = "action=something";
request.open('POST', url, true);
request.onreadystatechange = function() {if (request.readyState==4) alert("It worked!");};
request.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
request.setRequestHeader("Content-length", params.length);
request.setRequestHeader("Connection", "close");
request.send(params);

Ama kullanmak isterdim jQueryama işe yarayamıyorum. Denediğim şey bu:

$.ajax(url, {
    type:"POST",
    dataType:"json",
    data:{action:"something"}, 
    success:function(data, textStatus, jqXHR) {alert("success");},
    error: function(jqXHR, textStatus, errorThrown) {alert("failure");}
});

Bu, Başarısızlıkla sonuçlanır. Neden jQueryişe yaramadığını bilen varsa , lütfen bize bildirin. Teşekkürler.

( jQuery1.5.1 ve Firefox 4.0 kullanıyorum ve sunucum uygun bir Access-Control-Allow-Originbaşlık ile yanıt veriyor)


Ionic framework 3 ile CORS sorunları yaşarken benim için çözüm
buydu

Yanıtlar:


73

GÜNCELLEME: TimK'in belirttiği gibi, buna artık jquery 1.5.2 ile gerek kalmadı. Ancak, özel başlıklar eklemek veya kimlik bilgilerinin (kullanıcı adı, şifre veya çerezler, vb.) Kullanımına izin vermek istiyorsanız, okumaya devam edin.


Sanırım cevabı buldum! (4 saat ve bir sürü küfür sonra)

//This does not work!!
Access-Control-Allow-Headers: *

Kabul edeceğiniz tüm başlıkları manuel olarak belirtmeniz gerekir (en azından benim için FF 4.0 ve Chrome 10.0.648.204'te durum buydu).

jQuery'nin $ .ajax yöntemi, tüm etki alanları arası istekler için "x-istenilen-ile" başlığını gönderir (sanırım tek etki alanları arası).

Dolayısıyla, OPTIONS isteğine yanıt vermek için gereken eksik başlık şudur:

//no longer needed as of jquery 1.5.2
Access-Control-Allow-Headers: x-requested-with

"Basit" olmayan herhangi bir başlık aktarıyorsanız, bunları listenize eklemeniz gerekir (bir tane daha gönderirim):

//only need part of this for my custom header
Access-Control-Allow-Headers: x-requested-with, x-requested-by

Hepsini bir araya getirmek için işte PHP'im:

// * wont work in FF w/ Allow-Credentials
//if you dont need Allow-Credentials, * seems to work
header('Access-Control-Allow-Origin: http://www.example.com');
//if you need cookies or login etc
header('Access-Control-Allow-Credentials: true');
if ($this->getRequestMethod() == 'OPTIONS')
{
  header('Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS');
  header('Access-Control-Max-Age: 604800');
  //if you need special headers
  header('Access-Control-Allow-Headers: x-requested-with');
  exit(0);
}

5
JQuery 1.5.2'nin davranışını değiştirdiğini unutmayın. Artık bir "X-Requested-With" başlığı eklemez, bu nedenle bu artık bir sorun olmayabilir. blog.jquery.com/2011/03/31/jquery-152-released (Bug 8423)
Magmatik

1
@TimK, haklısın! 1.5.2'yi yayınladıklarını fark etmedim. Bununla birlikte, önceden uçuşa geçmeniz gerektiğinde de işe yarar. Cevabımı güncelledim.
Will Mason

Yani kafam karıştı. Yine de ara bir PHP betiği yazmak zorunda kaldınız mı? O halde Ajax kullanma konusunda endişelenmenize gerek yok, değil mi? Yoksa bir şey mi kaçırıyorum? Yalnızca JavaScript'in çözümü yok mu?
Elisabeth

1
@Elisabeth Bu yöntem yalnızca istenen hedefi kontrol ederseniz çalışır ... bu bir ara komut dosyası DEĞİLDİR. İstediğimiz konumun PHP'sinin en üstünde yer alır. Bu daha mantıklı mı?
Will Mason

2
Evet! teşekkürler Will. Her şeyi müşteri tarafından kontrol edebileceğini düşünmüştüm, ancak her iki ucun da kontrolüne ihtiyacın var gibi görünüyor.
Elisabeth

18

Başka bir olasılık da, ayarın dataType: jsonJQuery'nin Content-Type: application/jsonbaşlığı göndermesine neden olmasıdır . Bu, CORS tarafından standart olmayan bir başlık olarak kabul edilir ve bir CORS ön kontrol isteği gerektirir. Öyleyse denenecek birkaç şey:

1) Sunucunuzu uygun ön kontrol yanıtlarını gönderecek şekilde yapılandırmayı deneyin. Bu, Access-Control-Allow-Methodsve gibi ek başlıklar şeklinde olacaktır Access-Control-Allow-Headers.

2) dataType: jsonAyarı bırakın . JQuery talep etmelidir Content-Type: application/x-www-form-urlencodedvarsayılan olarak, ama sadece emin olmak için, o kadar değiştirebileceğiniz dataType: jsonilecontentType: 'application/x-www-form-urlencoded'


Fikirler için teşekkürler. DataType'ı ayarlamamayı application/x-www-form-urlencodedve ve hatta olmasını ayarlamayı denedim text/plain. Ve Access-Control-Allow-Methods "POST, GET, OPTIONS"hiçbir şey işe yaramadı yanıt başlığı eklemeyi denedim .
Magmatik

JavaScript hata konsoluna (veya Firebug konsoluna) bakıp istek sırasında herhangi bir hata olup olmadığını görebilir misiniz? Ayrıca, Wireshark'ı nasıl kullanacağınızı biliyorsanız, tel üzerinden geçen gerçek HTTP isteklerini görmek için bunu kullanabilirsiniz.
monsur

1
"Diğer bir olasılık da dataType: json ayarının JQuery'nin Content-Type: application / json başlığını göndermesine neden olmasıdır" - Bu olmaz. istek başlığını dataTypeetkiler, Acceptancak istek başlığını etkilemez Content-Type.
Quentin

9

Js'de "parametreler" gönderiyorsunuz: request.send(params);

ancak jquery'de "veri". Veri tanımlı mı ?: data:data,

Ayrıca, URL'de bir hata var:

$.ajax( {url:url,
         type:"POST",
         dataType:"json",
         data:data, 
         success:function(data, textStatus, jqXHR) {alert("success");},
         error: function(jqXHR, textStatus, errorThrown) {alert("failure");}
});

Sözdizimini $ .post için olanla karıştırıyorsunuz


Güncelleme : Monsur cevabına göre dolaşıyordum ve eklemeniz gerektiğini buldum Access-Control-Allow-Headers: Content-Type(aşağıda tam paragraf var)

http://metajack.im/2010/01/19/crossdomain-ajax-for-xmpp-http-binding-made-easy/

CORS Nasıl Çalışır?

CORS, Flash'ın crossdomain.xml dosyasına çok benzer şekilde çalışır. Temel olarak, tarayıcı bir hizmete etki alanları arası bir istek göndererek Origin HTTP başlığını istekte bulunan sunucuya ayarlar. Hizmet, böyle bir isteğe izin verilip verilmediğini belirtmek için Access-Control-Allow-Origin gibi birkaç başlık içerir.

BOSH bağlantı yöneticileri için Access-Control-Allow-Origin değerini * olarak ayarlayarak tüm kaynaklara izin verildiğini belirtmek yeterlidir. Content-Type üstbilgisi, Access-Control-Allow-Headers üstbilgisinde de beyaz listeye alınmalıdır.

Son olarak, BOSH bağlantı yöneticisi istekleri de dahil olmak üzere belirli türdeki istekler için izin kontrolü önceden yayınlanır. Tarayıcı bir OPTIONS isteğinde bulunacak ve hangi kaynaklara izin verildiğini, hangi yöntemlere izin verildiğini ve bu yetkilendirmenin ne kadar süreceğini gösteren bazı HTTP başlıklarını geri almayı bekler. Örneğin, OPTIONS için yaptığım Pencap ve ejabberd yamaları:

Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: GET, POST, OPTIONS
Access-Control-Allow-Headers: Content-Type 
Access-Control-Max-Age: 86400

1
Afedersiniz. Evet. var data = {action:"something"}
Magmatik

Her iki işlevin sözdizimini burada karşılaştırabilirsiniz: api.jquery.com/jQuery.post
Aleadam

Ayarlarda url ile denedim, ama aynı problem. .Ajax işlevi her iki şekilde de kullanılabilir.
Magmatik

Bu başlıklardan iki tanesine zaten sahiptim. Diğer ikisini ekledim. JQuery ile hala "başarısız". Düz javascript hala çalışıyor.
Magmatik

Aklıma gelen son şey, gönderilen farklı başlıkları ayarlamak ve oynamak için api.jquery.com/jQuery.ajaxSetup'ı kullanmaktır jQuery.ajaxSetup({'beforeSend': function(xhr) {xhr.setRequestHeader(string, string)}})(burada raylar için bir örnek: railscasts.com/episodes/136-jquery )
Aleadam

1

Cors, istek yöntemini tamamlanmadan önce POST'tan OPTIONS'a değiştirir, böylece gönderi verileriniz gönderilmez. Bu cors sorununu halletmenin yolu, OPTIONS yöntemini desteklemeyen ajax ile isteği gerçekleştirmektir. örnek kod:

        $.ajax({
            type: "POST",
            crossdomain: true,
            url: "http://localhost:1415/anything",
            dataType: "json",
            data: JSON.stringify({
                anydata1: "any1",
                anydata2: "any2",
            }),
            success: function (result) {
                console.log(result)
            },
            error: function (xhr, status, err) {
                console.error(xhr, status, err);
            }
        });

c # sunucusunda şu başlıklarla:

                    if (request.HttpMethod == "OPTIONS")
                    {
                          response.AddHeader("Access-Control-Allow-Headers", "Content-Type, Accept, X-Requested-With");
                          response.AddHeader("Access-Control-Allow-Methods", "GET, POST");
                          response.AddHeader("Access-Control-Max-Age", "1728000");
                    }
                    response.AppendHeader("Access-Control-Allow-Origin", "*");

-2

Jquery'nizi aşağıdaki şekilde değiştirin:

$.ajax({
            url: someurl,
            contentType: 'application/json',
            data: JSONObject,
            headers: { 'Access-Control-Allow-Origin': '*' }, //add this line
            dataType: 'json',
            type: 'POST',                
            success: function (Data) {....}
});

Ajax çağrılarımı neden eşzamanlı yapmak isteyeyim !?
Radko Dinev

contentType: 'application/json', data: JSONObject,- Sunucu JSON beklemiyor, bu yüzden JSON göndermek mantıklı olmaz. Ayrıca JSON Nesnesi diye bir şey yoktur .
Quentin

1
headers: { 'Access-Control-Allow-Origin': '*' }, //add this line- Bunu asla yapma. Access-Control-Allow-Originbir yanıt başlığıdır, istek başlığı değildir. En iyi ihtimalle bu hiçbir şey yapmaz. En kötüsü, isteği basit bir istekten önceden kontrol edilmiş bir isteğe dönüştürür ve bu da sunucuda işlem yapmayı daha da zorlaştırır.
Quentin
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.