อนุญาตส่วนหัว Access-Control-Allow-Origin โดยใช้ HTML5 fetch API


91

ฉันใช้ HTML5 fetch API

var request = new Request('https://davidwalsh.name/demo/arsenal.json');

fetch(request).then(function(response) {
    // Convert to JSON
    return response.json();
}).then(function(j) {
    // Yay, `j` is a JavaScript object
    console.log(JSON.stringify(j));
}).catch(function(error) {
    console.log('Request failed', error)
});

ฉันสามารถใช้ json ปกติ แต่ไม่สามารถดึงข้อมูลของ api url ด้านบนได้ มันแสดงข้อผิดพลาด:

ดึงข้อมูล API ไม่สามารถโหลดhttps://davidwalsh.name/demo/arsenal.json ไม่มีส่วนหัว "Access-Control-Allow-Origin" ในทรัพยากรที่ร้องขอ Origin ' http: // localhost ' จึงไม่ได้รับอนุญาตให้เข้าถึง หากการตอบกลับแบบทึบตอบสนองความต้องการของคุณให้ตั้งค่าโหมดของคำขอเป็น "no-cors" เพื่อดึงทรัพยากรโดยปิดใช้งาน CORS


เซิร์ฟเวอร์ของบุคคลที่สามจำเป็นต้องตั้งค่าไม่มีอะไรที่คุณสามารถทำได้บนไคลเอนต์
epascarello

@epascarello: เราสามารถทำได้ที่ฝั่งลูกค้า เบื้องหลังฉากคำขอ XHR กำลังเกิดขึ้น โปรดตรวจสอบสิ่งนี้https://davidwalsh.name/fetch
iNikkz

คำตอบ:


86

เช่นเดียวกับที่ epascarello กล่าวว่าเซิร์ฟเวอร์ที่โฮสต์ทรัพยากรจำเป็นต้องเปิดใช้งาน CORS สิ่งที่คุณสามารถทำได้ในฝั่งไคลเอ็นต์ (และอาจเป็นสิ่งที่คุณคิด) คือตั้งค่าโหมดการดึงข้อมูลไปที่ CORS (แม้ว่าจะเป็นค่าเริ่มต้นที่ฉันเชื่อก็ตาม):

fetch(request, {mode: 'cors'});

อย่างไรก็ตามสิ่งนี้ยังคงต้องใช้เซิร์ฟเวอร์เพื่อเปิดใช้งาน CORS ด้วยและอนุญาตให้โดเมนของคุณร้องขอทรัพยากร

ตรวจสอบเอกสารล ธและนี่วิดีโอ Udacity น่ากลัวอธิบายเดียวกันนโยบายแหล่งกำเนิดสินค้า

คุณยังสามารถใช้โหมด no-cors ในฝั่งไคลเอ็นต์ได้ แต่สิ่งนี้จะให้การตอบสนองแบบทึบ (คุณไม่สามารถอ่านเนื้อหาได้ แต่การตอบกลับยังคงถูกแคชโดยผู้ปฏิบัติงานบริการหรือใช้โดย API บางตัวเช่น<img>) :

fetch(request, {mode: 'no-cors'})
.then(function(response) {
  console.log(response); 
}).catch(function(error) {  
  console.log('Request failed', error)  
});

2
คุณสามารถอธิบายรายละเอียดเกี่ยวกับ "อย่างไรก็ตามยังต้องใช้เซิร์ฟเวอร์เพื่อเปิดใช้งาน CORS และอนุญาตให้โดเมนของคุณร้องขอทรัพยากร" ฉันมองหาคำแนะนำในการดำเนินการนั้นไม่สำเร็จ
jayscript

2
@jayscript กระบวนการโดยรวมจะมีลักษณะดังนี้: บนไคลเอนต์คำขอข้ามแหล่งที่มาจะสร้างขึ้นด้วยจาวาสคริปต์ ในกรณีของการดึงข้อมูล API โหมด 'cors' จะบอกเบราว์เซอร์ว่าสามารถส่งคำขอนี้ได้ หากคุณมีโหมด "ไม่มีคอร์" แทนเบราว์เซอร์จะหยุดคำขอเนื่องจากไม่ได้มาจากที่มาของแอปของคุณ เซิร์ฟเวอร์จะรับคำขอและตอบกลับ เบราว์เซอร์ยืนยันว่าการตอบสนองที่มีส่วนหัวล ธ เหมาะสมและถ้าเป็นเช่นนั้นช่วยให้การตอบสนองที่จะอ่าน หากไม่มีส่วนหัวเบราว์เซอร์จะแสดงข้อผิดพลาด
David Scales

1
@jayscript บทความ MDN นี้จะกล่าวถึงรายละเอียด โดยพื้นฐานแล้วเซิร์ฟเวอร์ของคุณต้องตั้งค่าส่วนหัวเหล่านี้: "Access-Control-Allow-Origin: foo.example ", "Access-Control-Allow-Methods: POST, GET, OPTIONS", "Access-Control-Allow-Headers: X-PINGOTHER, Content-Type "ซึ่งเปิดใช้งานต้นกำเนิดวิธีการและส่วนหัวตามลำดับ โดยทั่วไปจะใช้ "*" สำหรับส่วนหัวต้นทางคุณยังสามารถตรวจสอบเอกสาร Google นี้และ codelab ที่เกี่ยวข้องเพื่อเรียนรู้เกี่ยวกับ Fetch API: developers.google.com/web/ilt/pwa/working-with-the-fetch-api
David Scales

2
ขอขอบคุณ! ช่วยให้ฉันเข้าใจว่าเป็นไปไม่ได้ที่จะดึงข้อมูลจากเซิร์ฟเวอร์ API ที่มีต้นกำเนิดที่แตกต่างกันเมื่อเซิร์ฟเวอร์ API ไม่มีส่วนหัวใด ๆ ในกรณีเฉพาะที่ฉันกำลังจัดการฉันมีสิทธิ์เข้าถึงรหัสเซิร์ฟเวอร์ API และสามารถเพิ่มส่วนหัวได้ด้วยตัวเองซึ่งเปิดใช้งานการดึงข้อมูล
jayscript

นี่เป็นเรื่องโง่ปัญหาด้านความปลอดภัยของNO sendingคุกกี้คืออะไรจึงอนุญาตให้ CORS?
deathangel908

13

ฉันมีโค้ดฟรอนต์เอนด์ที่ทำงานในhttp: // localhost: 3000และ API ของฉัน (รหัสแบ็กเอนด์) ทำงานที่ http: // localhost: 5000

กำลังใช้ fetch API เพื่อเรียก API ในขั้นต้นเป็นการส่งข้อผิดพลาด "cors" จากนั้นเพิ่มโค้ดด้านล่างนี้ในรหัส Backend API ของฉันทำให้สามารถเริ่มต้นและส่วนหัวได้จากทุกที่

let allowCrossDomain = function(req, res, next) {
  res.header('Access-Control-Allow-Origin', "*");
  res.header('Access-Control-Allow-Headers', "*");
  next();
}
app.use(allowCrossDomain);

อย่างไรก็ตามคุณควร จำกัด ต้นกำเนิดของคุณในกรณีที่อยู่ในสภาพแวดล้อมอื่น ๆ เช่น stage, prod


21
นี่เป็นคำตอบที่แย่มาก นี่เป็นปัญหาด้านความปลอดภัยที่ใหญ่หลวง หากคุณกำลังอ่านข้อความนี้โปรดอย่าทำเช่นนี้
Mat Jones

1
นี่เป็นเพียงเล็กน้อยสำหรับการตั้งค่าภายในเครื่อง ตัวอย่างเช่นการทำภาพอย่างรวดเร็ว ใช่มีความเสี่ยงด้านความปลอดภัยหากเป็นเช่นเดียวกันกับสภาพแวดล้อมที่ปรับใช้งานได้อื่น ๆ สำหรับคนท้องถิ่นฉันรู้สึกว่ามันไม่ "อย่างไรก็ตามคุณควร จำกัด ต้นกำเนิดของคุณในกรณีของสภาพแวดล้อมอื่น ๆ เช่นเวทีแยง"
smsivaprakaash

12

สิ่งนี้ใช้ได้ผลสำหรับฉัน:

npm install -g local-cors-proxy

ปลายทาง API ที่เราต้องการขอที่มีปัญหา CORS:

https://www.yourdomain.com/test/list

เริ่ม Proxy:

lcp --proxyUrl https://www.yourdomain.com

 Proxy Active 

 Proxy Url: http://www.yourdomain.com:28080
 Proxy Partial: proxy
 PORT: 8010

จากนั้นในรหัสลูกค้าของคุณปลายทาง API ใหม่:

http://localhost:8010/proxy/test/list

ผลลัพธ์สุดท้ายจะเป็นการร้องขอไปยังhttps://www.yourdomain.ie/test/listโดยไม่มีปัญหา CORS!


โปรดตรวจสอบให้แน่ใจว่าเซิร์ฟเวอร์ทำงานแบบขนานเช่นเปิดหน้าต่างพรอมต์ cmt ใหม่แล้วรันโค้ด lcp --proxyUrl yourdomain.com
Govarthanan Venunathan

8

ฉันรู้ว่านี่เป็นโพสต์ที่เก่ากว่า แต่ฉันพบว่าสิ่งที่ใช้ได้ผลสำหรับฉันในการแก้ไขข้อผิดพลาดนี้คือการใช้ที่อยู่ IP ของเซิร์ฟเวอร์ของฉันแทนที่จะใช้ชื่อโดเมนในคำขอดึงข้อมูลของฉัน ตัวอย่างเช่น:

#(original) var request = new Request('https://davidwalsh.name/demo/arsenal.json');
#use IP instead
var request = new Request('https://0.0.0.0/demo/arsenal.json');

fetch(request).then(function(response) {
    // Convert to JSON
    return response.json();
}).then(function(j) {
    // Yay, `j` is a JavaScript object
    console.log(JSON.stringify(j));
}).catch(function(error) {
    console.log('Request failed', error)
});

1

หากคุณใช้ nginx ลองทำเช่นนี้

#Control-Allow-Origin access

    # Authorization headers aren't passed in CORS preflight (OPTIONS) calls. Always return a 200 for options.
    add_header Access-Control-Allow-Credentials "true" always;
    add_header Access-Control-Allow-Origin "https://URL-WHERE-ORIGIN-FROM-HERE " always;
    add_header Access-Control-Allow-Methods "GET,OPTIONS" always;
    add_header Access-Control-Allow-Headers "x-csrf-token,authorization,content-type,accept,origin,x-requested-with,access-control-allow-origin" always;

    if ($request_method = OPTIONS ) {
        return 200;
    }


1

คุณต้องตั้งค่าส่วนหัวของ cors ที่ฝั่งเซิร์ฟเวอร์ที่คุณกำลังขอข้อมูลจาก ตัวอย่างเช่นหากเซิร์ฟเวอร์แบ็กเอนด์ของคุณอยู่ใน Ruby บนรางให้ใช้รหัสต่อไปนี้ก่อนส่งการตอบกลับ ควรตั้งค่าส่วนหัวเดียวกันสำหรับเซิร์ฟเวอร์แบ็กเอนด์

headers['Access-Control-Allow-Origin'] = '*'
headers['Access-Control-Allow-Methods'] = 'POST, PUT, DELETE, GET, OPTIONS'
headers['Access-Control-Request-Method'] = '*'
headers['Access-Control-Allow-Headers'] = 'Origin, X-Requested-With, Content-Type, Accept, Authorization'

-3

ดูที่https://expressjs.com/en/resources/middleware/cors.html คุณต้องใช้ cors

ติดตั้ง:

$ npm install cors
const cors = require('cors');
app.use(cors());

คุณต้องใส่รหัสนี้ในเซิร์ฟเวอร์โหนดของคุณ


1
คุณจะรู้ได้อย่างไรว่าเป็นเซิร์ฟเวอร์ของ OP และถูกเขียนใน NodeJs?
Marek Szkudelski

หากคุณสร้างเซิร์ฟเวอร์โหนด (โหมดการพัฒนา) คุณสามารถใช้วิธีการนั้นเพื่อใช้การดึงข้อมูลใน js
Ernersto Pastori
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.