CORS - httprequest 'preflight' ทำอย่างไร?


94

ฉันกำลังพยายามส่งคำขอ HTTP ข้ามโดเมนไปยังบริการ WCF (ที่ฉันเป็นเจ้าของ) ฉันได้อ่านเทคนิคต่างๆในการทำงานกับข้อ จำกัด การเขียนสคริปต์ข้ามโดเมน เนื่องจากบริการของฉันต้องรองรับทั้งคำขอ GET และ POST ฉันจึงไม่สามารถติดตั้งแท็กสคริปต์แบบไดนามิกบางแท็กที่ src เป็น URL ของคำขอ GET เนื่องจากฉันมีอิสระที่จะทำการเปลี่ยนแปลงที่เซิร์ฟเวอร์ฉันจึงเริ่มพยายามใช้วิธีแก้ปัญหาที่เกี่ยวข้องกับการกำหนดค่าการตอบสนองของเซิร์ฟเวอร์เพื่อรวมส่วนหัว "Access-Control-Allow-Origin" และคำขอ "preflight" ด้วยและคำขอ OPTIONS ฉันได้แนวคิดจากโพสต์นี้: การทำให้ CORS ทำงานได้

ที่ฝั่งเซิร์ฟเวอร์วิธีการบนเว็บของฉันกำลังเพิ่ม 'Access-Control-Allow-Origin: *' ในการตอบสนอง HTTP ฉันเห็นว่าการตอบกลับรวมส่วนหัวนี้ไว้แล้ว คำถามของฉันคือฉันจะ 'กำหนดล่วงหน้า' คำขอ (OPTIONS) ได้อย่างไร? ฉันใช้ jQuery.getJSON เพื่อส่งคำขอ GET แต่เบราว์เซอร์ยกเลิกคำขอทันทีพร้อมกับสิ่งที่น่าอับอาย:

จุดกำเนิดhttp: // localhostไม่ได้รับอนุญาตจาก Access-Control-Allow-Origin

มีใครคุ้นเคยกับเทคนิค CORS นี้หรือไม่? ลูกค้าต้องทำการเปลี่ยนแปลงอะไรบ้างเพื่อตอบสนองคำขอของฉันล่วงหน้า

ขอบคุณ!

คำตอบ:


159

ในระหว่างการร้องขอ preflight คุณควรเห็นสองส่วนหัวต่อไปนี้: Access-Control-Request-Method และ Access-Control-Request-Headers ส่วนหัวของคำขอเหล่านี้กำลังขอสิทธิ์จากเซิร์ฟเวอร์เพื่อทำการร้องขอจริง การตอบกลับของคุณจำเป็นต้องรับทราบส่วนหัวเหล่านี้เพื่อให้คำขอใช้งานได้จริง

ตัวอย่างเช่นสมมติว่าเบราว์เซอร์ส่งคำขอโดยมีส่วนหัวต่อไปนี้:

Origin: http://yourdomain.com
Access-Control-Request-Method: POST
Access-Control-Request-Headers: X-Custom-Header

จากนั้นเซิร์ฟเวอร์ของคุณควรตอบสนองด้วยส่วนหัวต่อไปนี้:

Access-Control-Allow-Origin: http://yourdomain.com
Access-Control-Allow-Methods: GET, POST
Access-Control-Allow-Headers: X-Custom-Header

ให้ความสนใจเป็นพิเศษกับส่วนหัวการตอบกลับ Access-Control-Allow-Headers ค่าของส่วนหัวนี้ควรเป็นส่วนหัวเดียวกันในส่วนหัวของคำขอ Access-Control-Request-Headers และไม่สามารถเป็น "*" ได้

เมื่อคุณส่งการตอบกลับนี้ไปยังคำขอ preflight เบราว์เซอร์จะส่งคำขอจริง คุณสามารถเรียนรู้เพิ่มเติมเกี่ยวกับ CORS ได้ที่นี่: http://www.html5rocks.com/en/tutorials/cors/


คุณสามารถเพิ่มหลายโดเมนใน Access-Control-Allow-Origin ได้ไหม
botbot

@botbot คุณอาจจะทำสิ่งนี้ได้ในตอนนี้ แต่ในกรณีที่คนอื่นสงสัยว่าสามารถทำได้Access-Control-Allow-Origin: *
Steve Chambers

2
ฉันอาจจะพลาดอะไรบางอย่าง ฉันควรส่งคำขอ XMLHttp สองรายการหรือไม่ หนึ่งสำหรับไฟหน้า; ตรวจสอบการตอบสนองต่อความสำเร็จแล้วส่งแบบสอบถามจริง?
กังกัน

15
@ คุณกังกานต์ไม่ต้องกังวลเรื่องการส่งคำขอไฟล่วงหน้า หากคำขอต้องการไฟล่วงหน้าเบราว์เซอร์จะส่งให้คุณ
monsur

4
ขอบคุณสำหรับบิต 'ให้ความสนใจเป็นพิเศษ' ... ที่แก้ไขปัญหาของฉันเกี่ยวกับโหนด / Expressjs ฉันสามารถเพิ่มตัวกรองเพื่อตอบสนองคำขอ preflight เหล่านี้//cors and preflight filtering app.all('*', function(req, res, next){.. //preflight needs to return exact request-header res.set('Access-Control-Allow-Headers', req.headers['access-control-request-headers']); if ('OPTIONS' == req.method) return res.send(204);next(); });
Kurtfm

0

แม้ว่าชุดข้อความนี้จะย้อนกลับไปในปี 2014 แต่ปัญหานี้ยังคงเป็นปัจจุบันสำหรับพวกเราหลายคน นี่คือวิธีที่ฉันจัดการกับมันในบริบท jQuery 1.12 / PHP 5.6:

  • jQuery ส่งคำขอ XHR โดยใช้เฉพาะส่วนหัวที่ จำกัด ส่งเฉพาะ 'Origin' เท่านั้น
  • ไม่จำเป็นต้องมีการร้องขอไฟล่วงหน้า
  • เซิร์ฟเวอร์ต้องตรวจพบคำขอดังกล่าวเท่านั้นและเพิ่ม "Access-Control-Allow-Origin:" $ _SERVER ['HTTP_ORIGIN'] ส่วนหัวหลังจากตรวจพบว่านี่เป็น XHR ข้ามแหล่งกำเนิด

ตัวอย่างโค้ด PHP:

if (!empty($_SERVER['HTTP_ORIGIN'])) {
    // Uh oh, this XHR comes from outer space...
    // Use this opportunity to filter out referers that shouldn't be allowed to see this request
    if (!preg_match('@\.partner\.domain\.net$@'))
        die("End of the road if you're not my business partner.");

    // otherwise oblige
    header("Access-Control-Allow-Origin: " . $_SERVER['HTTP_ORIGIN']);
}
else {
    // local request, no need to send a specific header for CORS
}

โดยเฉพาะอย่างยิ่งอย่าเพิ่มexit;เนื่องจากไม่จำเป็นต้องใช้ไฟล่วงหน้า

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.