Permintaan CORS POST berfungsi dari JavaScript biasa, tetapi mengapa tidak dengan jQuery?

88

Saya mencoba membuat permintaan posting Cross Origin, dan saya membuatnya berfungsi dengan jelas JavaScriptseperti ini:

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

Tapi saya ingin menggunakan jQuery, tapi saya tidak bisa membuatnya bekerja. Inilah yang saya coba:

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

Ini menghasilkan Kegagalan. Jika ada yang tahu mengapa jQuerytidak berhasil, beri tahu kami semua. Terima kasih.

(Saya menggunakan jQuery1.5.1, dan Firefox 4.0, dan server saya merespons dengan Access-Control-Allow-Originheader yang tepat )

Magmatis
sumber
Ini adalah solusi bagi saya (gunakan XMLHttpRequest Javascript) saat menghadapi masalah CORS dengan framework Ionic 3.
jeudyx

Jawaban:

73

UPDATE: Seperti yang TimK tunjukkan, ini tidak diperlukan lagi dengan jquery 1.5.2. Tetapi jika Anda ingin menambahkan tajuk khusus atau mengizinkan penggunaan kredensial (nama pengguna, kata sandi, atau cookie, dll.), Baca terus.


Saya rasa saya menemukan jawabannya! (4 jam dan banyak kutukan nanti)

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

Anda perlu menentukan secara manual semua tajuk yang akan Anda terima (setidaknya itu yang saya alami di FF 4.0 & Chrome 10.0.648.204).

Metode $ .ajax jQuery mengirimkan header "x-diminta-dengan" untuk semua permintaan lintas domain (menurut saya ini hanya lintas domain).

Jadi header yang hilang yang diperlukan untuk menanggapi permintaan OPTIONS adalah:

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

Jika Anda meneruskan tajuk non "sederhana", Anda harus memasukkannya ke dalam daftar (saya mengirim satu lagi):

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

Jadi untuk menggabungkan semuanya, inilah PHP saya:

// * 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);
}
Will Mason
sumber
5
Perhatikan bahwa jQuery 1.5.2 telah mengubah perilakunya. Ini tidak lagi menambahkan tajuk "X-Diminta-Dengan", jadi ini mungkin tidak lagi menjadi masalah. blog.jquery.com/2011/03/31/jquery-152-released (Bug 8423)
Magmatic
1
@TimK, kamu benar! Saya tidak melihat mereka merilis 1.5.2. Karena itu, ini juga berfungsi jika Anda membutuhkannya untuk penerbangan sebelumnya. Saya telah memperbarui jawaban saya.
Will Mason
Jadi saya bingung. Anda akhirnya harus menulis skrip PHP perantara? Jadi Anda tidak perlu khawatir untuk menggunakan Ajax, bukan? Atau saya melewatkan sesuatu. Apakah tidak ada solusi khusus JavaScript?
Elisabeth
1
@Elisabeth Metode ini hanya bekerja jika Anda mengontrol tujuan yang diminta ... ini BUKAN skrip perantara. Ini adalah bagian atas PHP dari lokasi yang kami minta. Apakah itu lebih masuk akal?
Will Mason
2
Iya! terima kasih Will. Saya pikir Anda dapat mengontrol semuanya dari sisi klien, tetapi sepertinya Anda perlu mengontrol kedua ujungnya.
Elisabeth
18

Kemungkinan lain adalah pengaturan tersebut dataType: jsonmenyebabkan JQuery mengirimkan Content-Type: application/jsonheader. Ini dianggap sebagai header non-standar oleh CORS, dan memerlukan permintaan preflight CORS. Jadi beberapa hal untuk dicoba:

1) Coba konfigurasikan server Anda untuk mengirim tanggapan sebelum penerbangan yang benar. Ini akan menjadi header tambahan seperti Access-Control-Allow-Methodsdan Access-Control-Allow-Headers.

2) Jatuhkan dataType: jsonpengaturan. JQuery harus meminta Content-Type: application/x-www-form-urlencodedsecara default, tetapi untuk memastikan, Anda dapat mengganti dataType: jsondengancontentType: 'application/x-www-form-urlencoded'

monsur
sumber
Terima kasih atas idenya. Saya mencoba untuk tidak menyetel dataType, dan menyetelnya menjadi application/x-www-form-urlencodeddan genap text/plain. Dan saya mencoba menambahkan tajuk tanggapan Access-Control-Allow-Methods "POST, GET, OPTIONS"Tidak ada yang berhasil.
Magmatic
Dapatkah Anda melihat di konsol kesalahan JavaScript (atau konsol Firebug) dan melihat apakah ada kesalahan selama permintaan? Selain itu, jika Anda tahu cara menggunakan Wireshark, Anda dapat menggunakannya untuk melihat permintaan HTTP yang sebenarnya melalui kabel.
monsur
1
"Kemungkinan lain adalah bahwa pengaturan dataType: json menyebabkan JQuery mengirim header Content-Type: application / json" - Ini tidak terjadi. dataTypememengaruhi Acceptheader permintaan, tetapi tidak memengaruhi header Content-Typepermintaan.
Quentin
9

Anda mengirim "params" di js: request.send(params);

tetapi "data" di jquery ". Apakah data ditentukan ?: data:data,

Selain itu, Anda memiliki kesalahan di URL:

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

Anda mencampur sintaks dengan yang untuk $ .post


Pembaruan : Saya mencari-cari di Google berdasarkan jawaban monsur, dan saya menemukan bahwa Anda perlu menambahkan Access-Control-Allow-Headers: Content-Type(di bawah ini adalah paragraf lengkap)

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

Bagaimana CORS Bekerja

CORS bekerja sangat mirip dengan file crossdomain.xml Flash. Pada dasarnya, browser akan mengirimkan permintaan lintas-domain ke suatu layanan, menyetel asal HTTP header ke server yang meminta. Layanan ini menyertakan beberapa header seperti Access-Control-Allow-Origin untuk menunjukkan apakah permintaan semacam itu diizinkan.

Untuk manajer koneksi BOSH, cukup menentukan bahwa semua asal diperbolehkan, dengan mengatur nilai Access-Control-Allow-Origin ke *. Header Tipe Konten juga harus dicantumkan dalam daftar putih di header Access-Control-Allow-Headers.

Terakhir, untuk jenis permintaan tertentu, termasuk permintaan manajer koneksi BOSH, pemeriksaan izin akan dilakukan sebelumnya. Browser akan melakukan permintaan OPTIONS dan berharap mendapatkan kembali beberapa header HTTP yang menunjukkan asal yang diizinkan, metode mana yang diizinkan, dan berapa lama otorisasi ini akan bertahan. Misalnya, inilah patch Punjab dan ejabberd yang saya kembalikan untuk OPSI:

Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: GET, POST, OPTIONS
Access-Control-Allow-Headers: Content-Type 
Access-Control-Max-Age: 86400
Aleadam
sumber
1
Maaf. Iya. var data = {action:"something"}
Magmatic
Anda dapat membandingkan sintaks untuk kedua fungsi di sini: api.jquery.com/jQuery.post
Aleadam
Saya baru saja mencobanya dengan url di pengaturan, tetapi masalah yang sama. Fungsi .ajax bisa mengambil jalan lain.
Magmatic
Saya sudah memiliki dua dari header tersebut. Saya menambahkan dua lainnya. Masih "gagal" dengan jQuery. JavaScript biasa masih berfungsi.
Magmatic
Hal terakhir yang dapat saya pikirkan adalah menggunakan api.jquery.com/jQuery.ajaxSetup untuk mengatur jQuery.ajaxSetup({'beforeSend': function(xhr) {xhr.setRequestHeader(string, string)}})dan bermain dengan tajuk berbeda yang dikirim (contoh untuk rel di sini: railscasts.com/episodes/136-jquery )
Aleadam
1

Cors mengubah metode permintaan sebelum selesai, dari POST ke OPTIONS, jadi, data posting Anda tidak akan dikirim. Cara yang berhasil untuk menangani masalah cors ini, melakukan permintaan dengan ajax, yang tidak mendukung metode OPTIONS. kode contoh:

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

dengan header ini di c # server:

                    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", "*");
Lucas silva de souza sandim
sumber
-2

Ubah Jquery Anda dengan cara berikut:

$.ajax({
            url: someurl,
            contentType: 'application/json',
            data: JSONObject,
            headers: { 'Access-Control-Allow-Origin': '*' }, //add this line
            dataType: 'json',
            type: 'POST',                
            success: function (Data) {....}
});
Soma Sarkar
sumber
Mengapa saya ingin membuat calla Ajax saya sinkron !?
Radko Dinev
contentType: 'application/json', data: JSONObject,- Server tidak mengharapkan JSON, jadi mengirim JSON tidak masuk akal. Juga tidak ada yang namanya Objek JSON .
Quentin
1
headers: { 'Access-Control-Allow-Origin': '*' }, //add this line- Jangan lakukan itu. Access-Control-Allow-Originadalah header respons , bukan header permintaan. Paling banter ini tidak akan menghasilkan apa-apa. Paling buruk itu akan mengubah permintaan dari permintaan sederhana menjadi permintaan preflighted yang membuatnya lebih sulit untuk ditangani di server.
Quentin