คำขอ CORS POST ทำงานจาก JavaScript ธรรมดา แต่ทำไมไม่ใช้กับ jQuery


88

ฉันกำลังพยายามส่งคำขอโพสต์ Cross Origin และทำให้มันใช้JavaScriptงานได้ปกติดังนี้:

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

แต่ฉันต้องการใช้jQueryแต่ฉันไม่สามารถใช้งานได้ นี่คือสิ่งที่ฉันกำลังพยายาม:

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

ส่งผลให้เกิดความล้มเหลว หากใครทราบว่าเหตุใดจึงjQueryไม่ได้ผลโปรดแจ้งให้เราทราบ ขอบคุณ.

(ฉันใช้jQuery1.5.1 และ Firefox 4.0 และเซิร์ฟเวอร์ของฉันตอบสนองด้วยAccess-Control-Allow-Originส่วนหัวที่เหมาะสม)


นี่เป็นวิธีแก้ปัญหาสำหรับฉัน (ใช้ XMLHttpRequest ของ Javascript) ในขณะที่ประสบปัญหา CORS กับ Ionic framework 3
jeudyx

คำตอบ:


73

อัปเดต: ตามที่ TimK ชี้ให้เห็นสิ่งนี้ไม่จำเป็นกับ jquery 1.5.2 อีกต่อไป แต่ถ้าคุณต้องการเพิ่มส่วนหัวที่กำหนดเองหรืออนุญาตให้ใช้ข้อมูลรับรอง (ชื่อผู้ใช้รหัสผ่านหรือคุกกี้ ฯลฯ ) โปรดอ่านต่อ


ฉันคิดว่าฉันพบคำตอบแล้ว! (4 ชั่วโมงและมีการแช่งมากมายในภายหลัง)

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

คุณต้องระบุส่วนหัวทั้งหมดที่คุณจะยอมรับด้วยตนเอง (อย่างน้อยก็เป็นเช่นนั้นสำหรับฉันใน FF 4.0 และ Chrome 10.0.648.204)

เมธอด $ .ajax ของ jQuery ส่งส่วนหัว "x-request-with" สำหรับคำขอข้ามโดเมนทั้งหมด (ฉันคิดว่าเป็นเพียงการข้ามโดเมนเท่านั้น)

ดังนั้นส่วนหัวที่ขาดหายไปจึงจำเป็นในการตอบกลับคำขอ OPTIONS คือ:

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

หากคุณส่งผ่านส่วนหัวที่ไม่ "ธรรมดา" คุณจะต้องรวมไว้ในรายการของคุณ (ฉันจะส่งอีกหนึ่งรายการ):

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

ดังนั้นเพื่อรวบรวมทั้งหมดนี่คือ PHP ของฉัน:

// * 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 มีการเปลี่ยนแปลงลักษณะการทำงาน ไม่ได้เพิ่มส่วนหัว "X-Requested-With" อีกต่อไปดังนั้นนี่อาจไม่ใช่ปัญหาอีกต่อไป blog.jquery.com/2011/03/31/jquery-152-released (Bug 8423)
Magmatic

1
@ TimK คุณพูดถูก! ฉันไม่ได้สังเกตว่าพวกเขาปล่อย 1.5.2 ดังที่กล่าวมานี้ยังใช้งานได้หากคุณต้องการก่อนบิน ฉันได้อัปเดตคำตอบแล้ว
Will Mason

ดังนั้นฉันสับสน คุณต้องเขียนสคริปต์ PHP ระดับกลางหรือไม่? ดังนั้นคุณไม่จำเป็นต้องกังวลเกี่ยวกับการใช้ Ajax ใช่ไหม? หรือฉันขาดอะไรไป ไม่มีวิธีแก้ปัญหาเฉพาะ JavaScript หรือไม่?
Elisabeth

1
@Elisabeth วิธีนี้ใช้ได้เฉพาะเมื่อคุณควบคุมปลายทางที่ร้องขอ ... มันไม่ใช่สคริปต์กลาง เป็นอันดับต้น ๆ ของ PHP ของตำแหน่งที่เราร้องขอ มันสมเหตุสมผลกว่านี้ไหม
Will Mason

2
ใช่ ขอบคุณ Will. ฉันคิดว่าคุณสามารถควบคุมทุกอย่างได้จากฝั่งไคลเอ็นต์ แต่ดูเหมือนว่าคุณต้องการการควบคุมทั้งสองด้าน
Elisabeth

18

ความเป็นไปได้อีกประการหนึ่งคือการตั้งค่าdataType: jsonทำให้ JQuery ส่งContent-Type: application/jsonส่วนหัว นี่ถือเป็นส่วนหัวที่ไม่ได้มาตรฐานโดย CORS และต้องมีการร้องขอ CORS preflight ลองทำบางสิ่ง:

1) ลองกำหนดค่าเซิร์ฟเวอร์ของคุณเพื่อส่งการตอบสนองของไฟล่วงหน้าที่เหมาะสม นี้จะเป็นในรูปแบบของส่วนหัวเพิ่มเติมเช่นและAccess-Control-Allow-MethodsAccess-Control-Allow-Headers

2) วางการdataType: jsonตั้งค่า JQuery ควรร้องขอContent-Type: application/x-www-form-urlencodedตามค่าเริ่มต้น แต่เพื่อให้แน่ใจว่าคุณสามารถแทนที่dataType: jsonด้วยcontentType: 'application/x-www-form-urlencoded'


ขอบคุณสำหรับแนวคิด ฉันพยายามไม่ตั้งค่า dataType และตั้งค่าให้เป็นapplication/x-www-form-urlencodedและtext/plainสม่ำเสมอ และฉันพยายามเพิ่มส่วนหัวการตอบกลับของAccess-Control-Allow-Methods "POST, GET, OPTIONS"Nothing works
Magmatic

คุณสามารถดูในคอนโซลข้อผิดพลาดของ JavaScript (หรือคอนโซลของ Firebug) และดูว่ามีข้อผิดพลาดระหว่างการร้องขอหรือไม่ นอกจากนี้หากคุณรู้วิธีใช้ Wireshark คุณสามารถใช้สิ่งนั้นเพื่อดูคำขอ HTTP จริงที่ดำเนินการผ่านสาย
monsur

1
"ความเป็นไปได้อีกประการหนึ่งคือการตั้งค่า dataType: json ทำให้ JQuery ส่ง Content-Type: application / json header" - สิ่งนี้จะไม่เกิดขึ้น dataTypeมีผลต่อAcceptส่วนหัวของคำขอ แต่ไม่ใช่Content-Typeส่วนหัวของคำขอ
Quentin

9

คุณกำลังส่ง "params" ใน js: request.send(params);

แต่ "data" ใน jquery "มีการกำหนดข้อมูลหรือไม่: data:data,

นอกจากนี้คุณมีข้อผิดพลาดใน URL:

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

คุณกำลังผสมไวยากรณ์กับไวยากรณ์สำหรับ $ .post


อัปเดต : ฉันกำลัง googling ไปตามคำตอบของ monsur และฉันพบว่าคุณต้องเพิ่มAccess-Control-Allow-Headers: Content-Type(ด้านล่างคือย่อหน้าเต็ม)

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

CORS ทำงานอย่างไร

CORS ทำงานคล้ายกับไฟล์ crossdomain.xml ของ Flash โดยทั่วไปเบราว์เซอร์จะส่งคำขอข้ามโดเมนไปยังบริการโดยตั้งค่าต้นทางส่วนหัว HTTP ไปยังเซิร์ฟเวอร์ที่ร้องขอ บริการนี้มีส่วนหัวบางส่วนเช่น Access-Control-Allow-Origin เพื่อระบุว่าคำขอดังกล่าวได้รับอนุญาตหรือไม่

สำหรับตัวจัดการการเชื่อมต่อ BOSH ก็เพียงพอที่จะระบุว่าอนุญาตต้นกำเนิดทั้งหมดโดยตั้งค่าของ Access-Control-Allow-Origin เป็น * นอกจากนี้ส่วนหัวประเภทเนื้อหาจะต้องเป็นสีขาวในรายการส่วนหัว Access-Control-Allow-Headers

สุดท้ายสำหรับคำขอบางประเภทรวมถึงคำขอตัวจัดการการเชื่อมต่อ BOSH การตรวจสอบสิทธิ์จะถูกส่งล่วงหน้า เบราว์เซอร์จะส่งคำขอ OPTIONS และคาดว่าจะได้รับส่วนหัว HTTP กลับคืนซึ่งระบุว่าต้นกำเนิดใดได้รับอนุญาตวิธีการใดที่อนุญาตและระยะเวลาการอนุญาตนี้จะคงอยู่ ตัวอย่างเช่นนี่คือสิ่งที่แพทช์ปัญจาบและ ejabberd ที่ฉันส่งคืนสำหรับ OPTIONS:

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

1
ขออภัย. ใช่. var data = {action:"something"}
Magmatic

คุณสามารถเปรียบเทียบไวยากรณ์ของทั้งสองฟังก์ชันได้ที่นี่: api.jquery.com/jQuery.post
Aleadam

ฉันเพิ่งลองใช้ url ในการตั้งค่า แต่ปัญหาเดียวกัน ฟังก์ชัน. jax สามารถใช้วิธีใดก็ได้
Magmatic

ฉันมีสองส่วนหัวเหล่านั้นแล้ว ฉันเพิ่มอีกสองคน ยังคง "ล้มเหลว" กับ jQuery จาวาสคริปต์ธรรมดายังคงใช้งานได้
Magmatic

สิ่งสุดท้ายที่ฉันคิดได้คือใช้api.jquery.com/jQuery.ajaxSetupเพื่อตั้งค่าjQuery.ajaxSetup({'beforeSend': function(xhr) {xhr.setRequestHeader(string, string)}})และเล่นกับส่วนหัวต่างๆที่ส่งมา (ตัวอย่างสำหรับรางที่นี่: railscasts.com/episodes/136-jquery )
Aleadam

1

Cors เปลี่ยนวิธีการร้องขอก่อนที่จะเสร็จสิ้นจาก POST เป็น OPTIONS ดังนั้นข้อมูลโพสต์ของคุณจะไม่ถูกส่ง วิธีที่ใช้จัดการปัญหาคอร์นี้คือการดำเนินการตามคำขอด้วย ajax ซึ่งไม่รองรับเมธอด OPTIONS โค้ดตัวอย่าง:

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

                    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 ของคุณด้วยวิธีต่อไปนี้:

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

ทำไมฉันถึงต้องการทำให้ Ajax callas ซิงโครนัส!
Radko Dinev

contentType: 'application/json', data: JSONObject,- เซิร์ฟเวอร์ไม่ต้องการ JSON ดังนั้นการส่ง JSON จึงไม่สมเหตุสมผล นอกจากนี้ยังไม่มีสิ่งดังกล่าวเป็นวัตถุ JSON คือ
Quentin

1
headers: { 'Access-Control-Allow-Origin': '*' }, //add this line- อย่าทำอย่างนั้น Access-Control-Allow-Originเป็นส่วนหัวของการตอบกลับไม่ใช่ส่วนหัวของคำขอ อย่างดีที่สุดจะไม่ทำอะไรเลย ที่แย่ที่สุดก็จะแปลงคำขอจากคำขอธรรมดาไปเป็นคำขอที่เน้นไว้ล่วงหน้าซึ่งทำให้ยากต่อการจัดการกับเซิร์ฟเวอร์
Quentin
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.