เหตุใดฉันจึงได้รับคำขอ OPTIONS แทนคำขอ GET


289
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.js" type="text/javascript"></script>
<script>
$.get("http://example.com/", function(data) {
     alert(data);
});
</script>

มันจะร้องขอ OPTIONS ไปยัง URL นั้นจากนั้นจะไม่มีการโทรกลับด้วยสิ่งใด

เมื่อไม่ได้ข้ามโดเมนก็ใช้งานได้ดี

jQuery ไม่ควรโทรออกด้วย<script>โหนดแล้วโทรกลับเมื่อทำการโหลดหรือไม่ ฉันเข้าใจว่าฉันจะไม่สามารถรับผลลัพธ์ได้ (เนื่องจากเป็นข้ามโดเมน) แต่ก็ไม่เป็นไร ฉันแค่ต้องการให้สายผ่าน นี่เป็นข้อบกพร่องหรือฉันกำลังทำอะไรผิดหรือเปล่า?


2
อาจเป็นเพราะข้ามโดเมน เช่นถ้าคุณอยู่ในไฟล์ของคุณไฟล์: // PATH_TO_WEBSITE แทนที่จะใช้ localhost / WEBSITE_LINK
James111

คำตอบ:


263

ตามMDN ,

คำร้องขอล่วงหน้า

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

  • มันใช้วิธีการอื่นที่ไม่ใช่ GET หรือ POST นอกจากนี้หาก POST ใช้ในการส่งข้อมูลคำขอด้วย Content-Type นอกเหนือจาก application / x-www-form-urlencoded, multipart / form-data หรือ text / plain เช่นถ้าคำขอ POST ส่ง XML payload ไปยังเซิร์ฟเวอร์ ใช้ application / xml หรือ text / xml ดังนั้นการร้องขอจะถูก preflighted
  • มันตั้งค่าส่วนหัวที่กำหนดเองในคำขอ (เช่นคำขอใช้ส่วนหัวเช่น X-PINGOTHER)

44
นี้ได้รับการแก้ไขปัญหาของเราเปลี่ยนจาก "application / JSON" กับ "text / plain" หยุดตัวเลือกที่น่ากลัวขอ
Keeno

10
สิ่งที่ฉันไม่เข้าใจคือสาเหตุที่เบราว์เซอร์กำลังร้องขอด้วยวิธี OPTIONS เพียงเพื่อตรวจสอบว่าคำขอจริงนั้นปลอดภัยที่จะส่ง แต่ในแง่ใด ฉันหมายความว่าเซิร์ฟเวอร์ยังสามารถวางข้อ จำกัด กับส่วนหัวการตอบสนองบางอย่างดังนั้นทำไมจึงเป็นสิ่งจำเป็น?
hardik

11
@hardik โปรดจำไว้ว่าการเพิ่ม CORS คุณอาจยอมรับคำขอจากใครก็ได้ซึ่งพวกเขาสามารถจัดการข้อมูลบนเซิร์ฟเวอร์ของคุณผ่านการร้องขอ (POST, PUT, DELETE ฯลฯ ) ในสถานการณ์เหล่านี้เช่นเมื่อใช้ส่วนหัวที่กำหนดเองเบราว์เซอร์เพิ่งตรวจสอบกับเซิร์ฟเวอร์ก่อนว่าเซิร์ฟเวอร์ยินดีรับคำขอก่อนที่จะส่งเป็นการส่งคำขอที่ไม่พึงประสงค์ไปยังเซิร์ฟเวอร์อาจเป็นอันตรายต่อข้อมูลของคุณและสิ่งที่ จุดในเบราว์เซอร์ที่ส่ง payload ขนาดใหญ่ที่อาจเกิดขึ้นหากเซิร์ฟเวอร์ไม่ต้องการยอมรับพวกเขาดังนั้นตัวเลือกก่อนการบินจะตรวจสอบ
davidnknight

6
@davidnknight หากการส่งข้อมูลของคุณไปยังเซิร์ฟเวอร์อาจเป็นอันตรายซึ่งหมายความว่าเซิร์ฟเวอร์อาจถูกโจมตีจากนั้นแน่นอนว่าเซิร์ฟเวอร์ที่เป็นอันตรายจะตอบสนองต่อคำขอ OPTIONS ของคุณด้วย "แน่นอนส่งทั่ว!" ความปลอดภัยนั้นเป็นอย่างไร (คำถามเที่ยงตรง)
แมตต์

3
"คำขอ preflight ไม่ใช่เรื่องความปลอดภัย แต่เป็นสิ่งที่ไม่เปลี่ยนแปลง - กฎ" - ดูคำตอบของแรงจูงใจที่อยู่เบื้องหลังการแนะนำคำขอ preflight
FMJaguar


9

หากคุณกำลังพยายามโพสต์

ให้แน่ใจว่าข้อมูลในแบบฟอร์มและส่งของคุณJSON.stringifytext/plain

<form id="my-form" onSubmit="return postMyFormData();">
    <input type="text" name="name" placeholder="Your Name" required>
    <input type="email" name="email" placeholder="Your Email" required>
    <input type="submit" value="Submit My Form">
</form>

function postMyFormData() {

    var formData = $('#my-form').serializeArray();
    formData = formData.reduce(function(obj, item) {
        obj[item.name] = item.value;
        return obj;
    }, {});
    formData = JSON.stringify(formData);

    $.ajax({
        type: "POST",
        url: "https://website.com/path",
        data: formData,
        success: function() { ... },
        dataType: "text",
        contentType : "text/plain"
    });
}

2

ฉันไม่เชื่อว่า jQuery จะทำตามคำขอ JSONP ตามธรรมชาติเมื่อได้รับ URL เช่นนั้น อย่างไรก็ตามจะทำการร้องขอ JSONP เมื่อคุณบอกว่าอาร์กิวเมนต์ใดที่จะใช้สำหรับการโทรกลับ:

$.get("http://metaward.com/import/http://metaward.com/u/ptarjan?jsoncallback=?", function(data) {
     alert(data);
});

มันขึ้นอยู่กับสคริปต์ที่รับเพื่อใช้ประโยชน์จากข้อโต้แย้งนั้น (ซึ่งไม่จำเป็นต้องเรียกว่า "jsoncallback") ดังนั้นในกรณีนี้ฟังก์ชันจะไม่ถูกเรียกใช้ แต่เนื่องจากคุณระบุว่าคุณเพียงต้องการให้สคริปต์ที่ metaward.com ดำเนินการซึ่งจะทำให้สำเร็จ


การโทรกลับของฉันจะยังคงได้รับแจ้งว่าองค์ประกอบสคริปต์โหลดเต็มหรือไม่ ฉันแค่ต้องการให้แน่ใจว่าการอัปเดตเกิดขึ้นก่อนที่ฉันจะค้นหา API สำหรับมัน
Paul Tarjan

คุณจะได้รับหากสคริปต์ที่รองรับรองรับ JSONP และยินดีที่จะเรียกใช้ฟังก์ชันที่คุณระบุ หากสคริปต์ไม่ทำอะไรนอกจากสร้างบล็อกของข้อมูล JSON ที่ไม่มีลักษณะการทำงานอื่นคุณจะไม่สามารถบอกได้ว่าเมื่อโหลดเสร็จแล้ว หากจำเป็นต้องบอกเมื่อโหลดเสร็จคุณอาจลองใช้สคริปต์บนเซิร์ฟเวอร์ของคุณเองซึ่งทำหน้าที่เป็นพร็อกซี
VoteyDisciple

1

ในความเป็นจริงการขอข้ามโดเมน AJAX (XMLHttp) ไม่ได้รับอนุญาตเนื่องจากเหตุผลด้านความปลอดภัย (ลองนึกถึงการดึงเว็บเพจที่ "จำกัด " จากฝั่งไคลเอ็นต์และส่งกลับไปยังเซิร์ฟเวอร์ - นี่จะเป็นปัญหาด้านความปลอดภัย)

วิธีแก้ปัญหาเพียงอย่างเดียวคือการเรียกกลับ นี่คือ: การสร้างวัตถุสคริปต์ใหม่และชี้ src ไปยัง JavaScript ที่อยู่ด้านหลังซึ่งเป็นการเรียกกลับที่มีค่า JSON (myFunction ({data}), myFunction เป็นฟังก์ชันที่ทำบางอย่างกับข้อมูล (ตัวอย่างเช่นการเก็บไว้ ในตัวแปร)


1
ถูกต้อง แต่ฉันสามารถโหลดได้ใน <script src = ""> หรือ <img src = ""> และเบราว์เซอร์จะกดปุ่มอย่างมีความสุข ฉันแค่อยากรู้ว่าเมื่อไหร่ที่โหลดเต็มดังนั้นฉันสามารถสืบค้นผลลัพธ์ของการนำเข้าได้
Paul Tarjan

1

เพียงแค่เปลี่ยน "application / json" เป็น "text / plain" และอย่าลืม JSON.stringify (ขอ):

var request = {Company: sapws.dbName, UserName: username, Password: userpass};
    console.log(request);
    $.ajax({
        type: "POST",
        url: this.wsUrl + "/Login",
        contentType: "text/plain",
        data: JSON.stringify(request),

        crossDomain: true,
    });

1

ผมมีปัญหาเหมือนกัน. การแก้ไขของฉันคือการเพิ่มส่วนหัวในสคริปต์ PHP ของฉันซึ่งจะปรากฏเฉพาะเมื่ออยู่ในสภาพแวดล้อม dev

สิ่งนี้อนุญาตการร้องขอข้ามโดเมน:

header("Access-Control-Allow-Origin: *");

สิ่งนี้จะบอกคำขอ preflight ว่ามันเป็นเรื่องตกลงสำหรับลูกค้าที่จะส่งส่วนหัวใด ๆ ที่มันต้องการ:

header("Access-Control-Allow-Headers: *");

วิธีนี้ไม่จำเป็นต้องแก้ไขคำร้องขอ

หากคุณมีข้อมูลที่ละเอียดอ่อนในฐานข้อมูล dev ของคุณที่อาจรั่วไหลออกมาคุณอาจคิดถึงสองสิ่งนี้


1

ในกรณีของฉันปัญหาไม่เกี่ยวข้องกับ CORS เนื่องจากฉันออก jQuery POST ไปยังเว็บเซิร์ฟเวอร์เดียวกัน ข้อมูลคือ JSON แต่ฉันไม่ได้ระบุ dataType: 'json'

ฉันไม่มีพารามิเตอร์ contentType (และไม่เพิ่ม) ตามที่แสดงในคำตอบของ David Lopes ด้านบน


0

มันดูเหมือน Firefox และ Opera (ทดสอบบน mac ด้วย) ไม่ชอบความเป็นไขว้ของเรื่องนี้ (แต่ Safari ใช้ได้ดีกับมัน)

คุณอาจต้องเรียกรหัสด้านเซิร์ฟเวอร์ท้องถิ่นเพื่อม้วนหน้าระยะไกล


0

ฉันสามารถแก้ไขได้ด้วยความช่วยเหลือจากการติดตามส่วนหัว

Access-Control-Allow-Origin
Access-Control-Allow-Headers
Access-Control-Allow-Credentials
Access-Control-Allow-Methods

หากคุณอยู่ใน Nodejs นี่คือรหัสที่คุณสามารถคัดลอก / วางได้

app.use((req, res, next) => {
  res.header('Access-Control-Allow-Origin','*');
  res.header('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept');
  res.header('Access-Control-Allow-Credentials', true);
  res.header('Access-Control-Allow-Methods', 'GET, POST, PUT, PATCH');
  next();
});
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.