คำตอบนี้ครอบคลุมพื้นดินจำนวนมากดังนั้นจึงแบ่งออกเป็นสามส่วน:
- วิธีการใช้พร็อกซี CORS เพื่อแก้ไขปัญหา“ ไม่มีการเข้าถึงการควบคุมอนุญาตส่วนหัว”
- วิธีหลีกเลี่ยง CORS preflight
- วิธีการแก้ไขปัญหา“ การเข้าถึงการควบคุมอนุญาตให้กำเนิดต้องไม่ใช่ปัญหาของสัญลักษณ์แทน”
วิธีการใช้พร็อกซี CORS เพื่อแก้ไขปัญหา“ ไม่มีการเข้าถึงการควบคุมอนุญาตส่วนหัว”
หากคุณไม่ได้ควบคุมเซิร์ฟเวอร์โค้ด JavaScript ส่วนหน้าของคุณกำลังส่งคำขอไปและปัญหาเกี่ยวกับการตอบสนองจากเซิร์ฟเวอร์นั้นเป็นเพียงแค่การขาดAccess-Control-Allow-Origin
ส่วนหัวที่จำเป็นคุณยังสามารถทำงานได้โดยการขอผ่านทาง พร็อกซี CORS เพื่อแสดงวิธีการทำงานขั้นแรกนี่คือโค้ดบางส่วนที่ไม่ได้ใช้พร็อกซี CORS:
const url = "https://example.com"; // site that doesn’t send Access-Control-*
fetch(url)
.then(response => response.text())
.then(contents => console.log(contents))
.catch(() => console.log("Can’t access " + url + " response. Blocked by browser?"))
เหตุผลที่บล็อกได้รับการตีมีป้องกันเบราว์เซอร์ที่รหัสจากการเข้าถึงการตอบสนองที่กลับมาจากcatch
https://example.com
และสาเหตุที่เบราว์เซอร์ทำนั่นคือการตอบสนองขาดAccess-Control-Allow-Origin
ส่วนหัวการตอบสนอง
ตอนนี้นี่เป็นตัวอย่างเดียวกัน แต่เพิ่มพร็อกซี CORS ใน:
const proxyurl = "https://cors-anywhere.herokuapp.com/";
const url = "https://example.com"; // site that doesn’t send Access-Control-*
fetch(proxyurl + url) // https://cors-anywhere.herokuapp.com/https://example.com
.then(response => response.text())
.then(contents => console.log(contents))
.catch(() => console.log("Can’t access " + url + " response. Blocked by browser?"))
หมายเหตุ: หาก https://cors-anywhere.herokuapp.com ไม่ทำงานหรือไม่พร้อมใช้งานเมื่อคุณลองใช้ดูวิธีการปรับใช้เซิร์ฟเวอร์ CORS Anywhere ของคุณเองที่ Heroku ในเวลาเพียง 2-3 นาที
รหัสสองตัวอย่างข้างต้นสามารถเข้าถึงการตอบสนองที่ประสบความสำเร็จเพราะการ URL ที่ร้องขอและเปลี่ยนไปhttps://cors-anywhere.herokuapp.com/https://example.com -by เพียง prefixing ด้วยพร็อกซี URL ของสาเหตุที่ทำให้ ขอให้ทำผ่านพร็อกซี่นั้นซึ่ง:
https://example.com
ส่งต่อการร้องขอไปยัง
https://example.com
ได้รับการตอบสนองจาก
- เพิ่ม
Access-Control-Allow-Origin
ส่วนหัวในการตอบกลับ
- ผ่านการตอบกลับนั้นโดยมีส่วนหัวที่เพิ่มกลับไปยังรหัสส่วนหน้าที่ร้องขอ
เบราว์เซอร์อนุญาตให้โค้ดส่วนหน้าสามารถเข้าถึงการตอบสนองได้เนื่องจากการตอบสนองที่มีAccess-Control-Allow-Origin
ส่วนหัวการตอบสนองคือสิ่งที่เบราว์เซอร์เห็น
คุณสามารถเรียกใช้พร็อกซี่ของคุณเองโดยใช้รหัสได้อย่างง่ายดายจากhttps://github.com/Rob--W/cors-anywhere/
คุณสามารถปรับใช้พร็อกซีของคุณเองกับ Heroku ได้อย่างง่ายดายในเวลาเพียง 2-3 นาทีโดยมี 5 คำสั่ง:
git clone https://github.com/Rob--W/cors-anywhere.git
cd cors-anywhere/
npm install
heroku create
git push heroku master
หลังจากใช้คำสั่งเหล่านั้นคุณจะจบลงด้วยเซิร์ฟเวอร์ล ธ ทุกที่ของคุณเองทำงานที่เช่นhttps://cryptic-headland-94862.herokuapp.com/ ดังนั้นแทนที่จะนำหน้า URL คำขอของคุณด้วยhttps://cors-anywhere.herokuapp.com
นำหน้าแทนด้วย URL สำหรับอินสแตนซ์ของคุณเอง เช่นhttps://cryptic-headland-94862.herokuapp.com/https://example.com
ดังนั้นหากคุณลองใช้ https://cors-anywhere.herokuapp.com คุณจะพบว่ามันไม่ทำงาน (ซึ่งบางครั้งมันจะเป็น) ให้พิจารณารับบัญชี Heroku (ถ้าคุณยังไม่ได้) และใช้เวลา 2 หรือ 3 นาทีเพื่อทำตามขั้นตอนด้านบนเพื่อปรับใช้เซิร์ฟเวอร์ CORS Anywhere ของคุณเองใน Heroku
ไม่ว่าคุณจะเรียกใช้ของคุณเองหรือใช้https://cors-anywhere.herokuapp.comหรือเปิดพร็อกซีอื่น ๆ โซลูชันนี้จะทำงานแม้ว่าคำขอจะเป็นตัวกระตุ้นให้เบราว์เซอร์ทำการOPTIONS
ร้องขอCORS preflight— เพราะในกรณีนั้น พร็อกซียังส่งกลับAccess-Control-Allow-Headers
และAccess-Control-Allow-Methods
ส่วนหัวที่จำเป็นเพื่อให้ preflight ประสบความสำเร็จ
วิธีหลีกเลี่ยง CORS preflight
รหัสในคำถามทริกเกอร์ CORS preflight— เนื่องจากส่งAuthorization
ส่วนหัว
https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS#Preflighted_requests
แม้ว่าจะไม่มีContent-Type: application/json
ส่วนหัวก็ตามก็จะทำให้เกิด preflight
ความหมาย“ preflight” หมายถึง: ก่อนที่เบราว์เซอร์จะพยายามPOST
ในรหัสในคำถามก่อนอื่นมันจะส่งOPTIONS
คำขอไปยังเซิร์ฟเวอร์ - เพื่อตรวจสอบว่าเซิร์ฟเวอร์เลือกที่จะรับ cross-origin POST
ซึ่งรวมถึงส่วนหัวAuthorization
และContent-Type: application/json
มันทำงานได้ค่อนข้างดีด้วยสคริปต์ม้วนเล็ก ๆ - ฉันได้รับข้อมูลของฉัน
ในการทดสอบอย่างถูกต้องcurl
คุณต้องเลียนแบบOPTIONS
คำขอpreflight ที่เบราว์เซอร์ส่ง:
curl -i -X OPTIONS -H "Origin: http://127.0.0.1:3000" \
-H 'Access-Control-Request-Method: POST' \
-H 'Access-Control-Request-Headers: Content-Type, Authorization' \
"https://the.sign_in.url"
… https://the.sign_in.url
แทนที่ด้วยsign_in
URL ที่แท้จริงของคุณ
การตอบกลับที่เบราว์เซอร์จำเป็นต้องดูจากOPTIONS
คำขอนั้นต้องมีส่วนหัวดังนี้:
Access-Control-Allow-Origin: http://127.0.0.1:3000
Access-Control-Allow-Methods: POST
Access-Control-Allow-Headers: Content-Type, Authorization
หากการOPTIONS
ตอบสนองไม่รวมส่วนหัวเหล่านั้นเบราว์เซอร์จะหยุดอยู่ตรงนั้นและไม่เคยพยายามส่งPOST
คำขอ นอกจากนี้รหัสสถานะ HTTP สำหรับการตอบสนองจะต้องเป็น 2xx โดยทั่วไปคือ 200 หรือ 204 หากเป็นรหัสสถานะอื่น ๆ เบราว์เซอร์จะหยุดอยู่ที่นั่น
เซิร์ฟเวอร์ในคำถามกำลังตอบกลับOPTIONS
คำขอด้วยรหัสสถานะ 501 ซึ่งเห็นได้ชัดว่าหมายความว่าพยายามระบุว่าไม่ได้ใช้การสนับสนุนOPTIONS
คำขอ เซิร์ฟเวอร์อื่นมักตอบกลับด้วยรหัสสถานะ 405“ วิธีที่ไม่อนุญาต” ในกรณีนี้
ดังนั้นคุณจะไม่สามารถPOST
ส่งคำขอไปยังเซิร์ฟเวอร์นั้นโดยตรงจากโค้ด JavaScript ส่วนหน้าของคุณหากเซิร์ฟเวอร์ตอบสนองOPTIONS
คำขอนั้นด้วย 405 หรือ 501 หรือสิ่งอื่นใดนอกเหนือจาก 200 หรือ 204 หรือหากไม่ตอบสนองต่อสิ่งที่จำเป็น ส่วนหัวการตอบสนอง
วิธีที่จะหลีกเลี่ยงการเรียก preflight สำหรับกรณีในคำถามจะเป็น:
- หากเซิร์ฟเวอร์ไม่ต้องการ
Authorization
ส่วนหัวคำขอ แต่ให้แทนที่ (ตัวอย่าง) อาศัยข้อมูลการตรวจสอบความถูกต้องที่ฝังอยู่ในเนื้อความของPOST
คำขอหรือเป็นพารามิเตอร์การสืบค้น
- ถ้าเซิร์ฟเวอร์ไม่ต้องการให้
POST
เนื้อความมีContent-Type: application/json
ชนิดสื่อบันทึก แต่ยอมรับPOST
เนื้อความเช่นเดียวapplication/x-www-form-urlencoded
กับพารามิเตอร์ที่ชื่อjson
(หรืออะไรก็ตาม) ที่มีค่าเป็นข้อมูล JSON
วิธีการแก้ไขปัญหา“ การเข้าถึงการควบคุมอนุญาตให้กำเนิดต้องไม่ใช่ปัญหาของสัญลักษณ์แทน”
ฉันได้รับข้อความแสดงข้อผิดพลาดอื่น:
ค่าของส่วนหัว 'Access-Control-Allow-Origin' ในการตอบกลับจะต้องไม่ใช่สัญลักษณ์แทน '*' เมื่อโหมดข้อมูลรับรองของคำขอคือ 'รวม' Origin ' http://127.0.0.1:3000 ' จึงไม่ได้รับอนุญาตให้เข้าถึง โหมดหนังสือรับรองของคำร้องขอที่เริ่มต้นโดย XMLHttpRequest ถูกควบคุมโดยแอ็ตทริบิวต์ withCredentials
สำหรับคำขอที่มีข้อมูลประจำตัวที่เบราว์เซอร์จะไม่ยอมให้การเข้าถึงรหัส JavaScript ส่วนหน้าของคุณตอบสนองถ้าค่าของส่วนหัวของการตอบสนองAccess-Control-Allow-Origin
แทนค่าในกรณีที่ต้องตรงกับต้นกำเนิดรหัสส่วนหน้าของคุณ*
http://127.0.0.1:3000
ดูคำร้องขอและสัญลักษณ์แทนในบทความ MDN HTTP access control (CORS)
หากคุณควบคุมเซิร์ฟเวอร์ที่คุณกำลังส่งคำขอไปดังนั้นวิธีทั่วไปในการจัดการกับกรณีนี้คือการกำหนดค่าเซิร์ฟเวอร์ให้ใช้ค่าของOrigin
ส่วนหัวคำขอและ echo / สะท้อนกลับเข้าไปในค่าของAccess-Control-Allow-Origin
ส่วนหัวการตอบกลับ ตัวอย่างเช่นกับ nginx:
add_header Access-Control-Allow-Origin $http_origin
แต่นั่นเป็นเพียงตัวอย่างเดียว ระบบเซิร์ฟเวอร์อื่น ๆ (เว็บ) ให้วิธีที่คล้ายกันเพื่อสะท้อนค่าเริ่มต้น
ฉันกำลังใช้ Chrome ฉันลองใช้ปลั๊กอิน Chrome CORS ด้วย
ปลั๊กอิน Chrome CORS นั้นเห็นได้ชัดว่าเพียงแค่แทรกAccess-Control-Allow-Origin: *
ส่วนหัวลงในการตอบสนองที่เบราว์เซอร์เห็น หากปลั๊กอินได้อย่างชาญฉลาดในสิ่งที่มันจะทำคือการตั้งค่าของปลอมว่าAccess-Control-Allow-Origin
ส่วนหัวของการตอบสนองต่อการกำเนิดที่แท้จริงของโค้ด JavaScript http://127.0.0.1:3000
ส่วนหน้าของคุณ
ดังนั้นควรหลีกเลี่ยงการใช้ปลั๊กอินนั้นแม้แต่ในการทดสอบ มันเป็นเพียงความว้าวุ่นใจ หากคุณต้องการทดสอบการตอบสนองที่คุณได้รับจากเซิร์ฟเวอร์โดยที่ไม่มีเบราว์เซอร์กรองคุณควรใช้curl -H
ตามที่กล่าวไว้ข้างต้น
เท่าที่รหัส JavaScript frontend สำหรับfetch(…)
คำขอในคำถาม:
headers.append('Access-Control-Allow-Origin', 'http://localhost:3000');
headers.append('Access-Control-Allow-Credentials', 'true');
ลบบรรทัดเหล่านั้น Access-Control-Allow-*
ส่วนหัวที่มีการตอบสนองที่ส่วนหัว คุณไม่ต้องการที่จะส่งพวกเขาในการร้องขอ เอฟเฟ็กต์อย่างเดียวที่จะมีคือการเปิดให้เบราว์เซอร์ทำการ preflight