ทำไมบุรุษไปรษณีย์ไม่ได้รับข้อผิดพลาด“ ไม่มีการเข้าถึง - การควบคุม - อนุญาต - กำเนิด” ในทรัพยากรที่ร้องขอ” เมื่อรหัส JavaScript ของฉันไม่ทำงาน


2500

Mod note : คำถามนี้เกี่ยวกับสาเหตุที่บุรุษไปรษณีย์ไม่อยู่ภายใต้ข้อ จำกัด ของ CORS ในลักษณะเดียวกับ XMLHttpRequest คำถามนี้ไม่ได้เกี่ยวกับวิธีการแก้ไขข้อผิดพลาด "ไม่ 'การเข้าถึงการควบคุมการอนุญาตให้กำเนิด' ... "

กรุณาหยุดโพสต์ :

  • การกำหนดค่า CORS สำหรับทุกภาษา / กรอบภายใต้ดวงอาทิตย์ แทนที่จะหา / คำถามกรอบของภาษาที่เกี่ยวข้องของคุณ
  • บริการของบุคคลที่สามที่อนุญาตให้มีการร้องขอเพื่อหลีกเลี่ยง CORS
  • ตัวเลือกบรรทัดคำสั่งสำหรับการปิด CORS สำหรับเบราว์เซอร์ต่างๆ

ฉันกำลังพยายามที่จะทำการอนุญาตใช้งาน JavaScriptโดยการเชื่อมต่อไปยังสงบ APIในตัวขวด อย่างไรก็ตามเมื่อฉันขอฉันได้รับข้อผิดพลาดดังต่อไปนี้:

XMLHttpRequest ไม่สามารถโหลดhttp: // myApiUrl / เข้าสู่ระบบ ไม่มีส่วนหัว 'Access-Control-Allow-Origin' บนทรัพยากรที่ร้องขอ จุดเริ่มต้น 'null' ไม่อนุญาตให้เข้าถึง

ฉันรู้ว่า API หรือทรัพยากรระยะไกลต้องตั้งค่าส่วนหัว แต่ทำไมมันทำงานเมื่อฉันทำคำขอผ่านบุรุษไปรษณีย์ส่วนขยายของ Chrome ?

นี่คือรหัสคำขอ:

$.ajax({
    type: "POST",
    dataType: 'text',
    url: api,
    username: 'user',
    password: 'pass',
    crossDomain : true,
    xhrFields: {
        withCredentials: true
    }
})
    .done(function( data ) {
        console.log("done");
    })
    .fail( function(xhr, textStatus, errorThrown) {
        alert(xhr.responseText);
        alert(textStatus);
    });

32
คุณกำลังทำคำขอจาก localhost หรือรัน HTML อย่างรุนแรงหรือไม่?
นพ. Sahib Bin Mahboob

@ MD.SahibBinMahboob ถ้าฉันเข้าใจคำถามของคุณฉันจะขอจาก localhost - ฉันมีหน้าบนคอมพิวเตอร์ของฉันและเพียงแค่เรียกใช้ เมื่อฉันปรับใช้ไซต์ในการโฮสต์มันให้ผลลัพธ์เหมือนกัน
นายเจได

6
เกี่ยวข้องกันมาก: stackoverflow.com/questions/10143093/…
cregox

8
สำหรับทุกคนที่กำลังมองหาการอ่านเพิ่มเติม MDN มีบทความที่ดีเกี่ยวกับการร้องขอ ajax และ cross origin: developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS
Sam Eaton

1
หมายเหตุสำคัญหนึ่งสำหรับข้อผิดพลาดประเภทนี้ในโหนด js คุณต้องตั้งค่าส่วนหัวการเข้าถึงของคุณในการเริ่มต้นไฟล์ server.js ก่อนเริ่มต้นการตั้งค่าเส้นทางของคุณ มิฉะนั้นทุกอย่างจะทำงานได้ดี แต่คุณจะได้รับข้อผิดพลาดนี้เมื่อคุณทำการร้องขอจากแอพของคุณ
Alex J

คำตอบ:


1345

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

เมื่อคุณใช้บุรุษไปรษณีย์พวกเขาจะไม่ถูก จำกัด โดยนโยบายนี้ อ้างถึงจากXMLHttpRequest Cross-Origin :

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


7
คุณถูก. ฉันขอโดเมนที่ต่างจากหน้าของฉันคือ API อยู่บนเซิร์ฟเวอร์และฉันเรียกใช้การร้องขอจาก localhost ก่อนที่ฉันจะยอมรับคำตอบคุณสามารถอธิบายได้ว่าอะไรคือ "การดำเนินการตามคำขอโดยตรง" POSTMAN ไม่ได้ใช้โดเมนหรือ
นายเจได

181
เบราว์เซอร์ไม่ได้บล็อกการร้องขอ เบราว์เซอร์เท่านั้นที่บล็อกการร้องขอ ajax ไขว้ได้ทันทีคือ IE7 หรือเก่ากว่า เบราว์เซอร์ทั้งหมดนอกเหนือจาก IE7 และเก่ากว่านั้นใช้งาน CORS spec (IE8 & IE9 บางส่วน) สิ่งที่คุณต้องทำคือเลือกใช้คำขอ CORS บนเซิร์ฟเวอร์ API ของคุณโดยส่งคืนหัวเรื่องที่เหมาะสมตามคำขอ คุณควรอ่านข้อมูลเกี่ยวกับแนวความคิดที่ล ธmzl.la/VOFrSz บุรุษไปรษณีย์ส่งคำขอผ่าน XHR เช่นกัน หากคุณไม่เห็นปัญหาเดียวกันเมื่อใช้บุรุษไปรษณีย์นั่นหมายความว่าคุณไม่ได้ส่งคำขอเดียวกันผ่านบุรุษไปรษณีย์โดยไม่รู้ตัว
เรย์นิโคลัส

10
@ MD.SahibBinMahboob บุรุษไปรษณีย์ไม่ส่งคำขอ "จาก java / python ของคุณ" รหัส มันจะส่งคำขอโดยตรงจากเบราว์เซอร์ XHR ในส่วนขยายของ Chrome ทำงานแตกต่างกันเล็กน้อยโดยเฉพาะอย่างยิ่งเมื่อมีการร้องขอข้ามกำเนิดมีส่วนร่วม
เรย์นิโคลัส

249

คำเตือน:การใช้Access-Control-Allow-Origin: *สามารถทำให้ API / เว็บไซต์ของคุณเสี่ยงต่อการถูกโจมตีด้วยการปลอมแปลง (CSRF) ให้แน่ใจว่าคุณเข้าใจความเสี่ยงก่อนที่จะใช้รหัสนี้

มันง่ายมากที่จะแก้หากคุณกำลังใช้PHP เพียงเพิ่มสคริปต์ต่อไปนี้ในตอนต้นของหน้า PHP ซึ่งจัดการคำขอ:

<?php header('Access-Control-Allow-Origin: *'); ?>

หากคุณใช้Node-redคุณต้องอนุญาตให้CORSในnode-red/settings.jsไฟล์โดยไม่แสดงความคิดเห็นในบรรทัดต่อไปนี้:

// The following property can be used to configure cross-origin resource sharing
// in the HTTP nodes.
// See https://github.com/troygoode/node-cors#configuration-options for
// details on its contents. The following is a basic permissive set of options:
httpNodeCors: {
 origin: "*",
 methods: "GET,PUT,POST,DELETE"
},

หากคุณใช้Flaskเหมือนคำถาม คุณต้องติดตั้งก่อนflask-cors

$ pip install -U flask-cors

จากนั้นรวม Flors cors ในแอปพลิเคชันของคุณ

from flask_cors import CORS

แอปพลิเคชั่นที่เรียบง่ายจะมีลักษณะดังนี้:

from flask import Flask
from flask_cors import CORS

app = Flask(__name__)
CORS(app)

@app.route("/")
def helloWorld():
  return "Hello, cross-origin-world!"

สำหรับรายละเอียดเพิ่มเติมคุณสามารถตรวจสอบเอกสารขวด


93
และมันไม่ปลอดภัย
llazzaro

153
คุณไม่ควรปิด CORS เพราะคุณไม่รู้ว่ามันคืออะไร นี่คือคำตอบที่น่ากลัว
meagar

124
แม้ว่ามันอาจจะไม่ปลอดภัยคำถามก็ไม่ได้เกี่ยวกับความปลอดภัย แต่จะทำอย่างไรให้สำเร็จ นี่คือหนึ่งในตัวเลือกที่นักพัฒนาซอฟต์แวร์ต้องเลือกเมื่อจัดการกับคำขอ AJAX ข้ามโดเมน มันช่วยฉันแก้ปัญหาและสำหรับแอปพลิเคชันของฉันฉันไม่สนใจว่าข้อมูลมาจากไหน ฉันฆ่าเชื้ออินพุตทั้งหมดด้วย PHP บนโดเมนปลายทางดังนั้นถ้ามีคนต้องการโพสต์ขยะให้ลองพวกเขา จุดหลักที่นี่คือ AJAX ข้ามโดเมนสามารถได้รับอนุญาตจากโดเมนปลายทาง +1 สำหรับคำตอบ
ZurabWeb

23
ในขณะที่ฉันเห็นด้วยกับข้อความทั่วไปที่ Piero ให้นั่นไม่ใช่เรื่องความปลอดภัยโดยเฉพาะ แต่เรื่องความปลอดภัยเป็นเรื่องที่น่ากังวล ฉันคิดว่าสิ่งนี้ควรมีอย่างน้อยพูดอะไรบางอย่างเช่น "นี่เป็นเรื่องไม่ดีโดยทั่วไปอย่าทำสิ่งนี้จนกว่าคุณจะรู้ว่าคุณกำลังทำอะไร! ฉันเกลียดที่จะมีคนมาที่นี่และแค่คิดว่า "โอ้ฉันสามารถเพิ่ม / ปรับส่วนหัวนี้ได้และฉันก็ทำได้ดี!" และไม่รู้การแตกกิ่งก้านสาขาเต็ม ฉันหมายความว่ามันเป็นเรื่องเกี่ยวกับพวกเขาในการวิจัยและทั้งหมด แต่ก็ยัง
โธมัสเอฟ

4
ผมชอบคำตอบนี้ ... ฉันมีปัญหาเดียวกันและจะแก้มัน ... เขาอธิบายว่ามีบางประเด็นที่การรักษาความปลอดภัย แต่ที่เกิดปัญหาอื่นและให้ทุกคนเป็นรายคิดและการแก้ปัญหาว่าปัญหา ...
อารีย์ Waisberg

63

เนื่องจาก
$ .ajax ({type: "POST" - เรียกOPTIONS
$ .post ( - โทรPOST

ทั้งสองต่างกัน บุรุษไปรษณีย์เรียกว่า "POST" อย่างถูกต้อง แต่เมื่อเราเรียกมันว่ามันจะเป็น "OPTIONS"

สำหรับ C # web services - Web API

โปรดเพิ่มรหัสต่อไปนี้ในไฟล์web.configของคุณภายใต้แท็ก <system.webServer> สิ่งนี้จะได้ผล:

<httpProtocol>
    <customHeaders>
        <add name="Access-Control-Allow-Origin" value="*" />
    </customHeaders>
</httpProtocol>

โปรดตรวจสอบว่าคุณไม่ได้ทำผิดพลาดใด ๆ ในการโทร Ajax

jQuery

$.ajax({
    url: 'http://mysite.microsoft.sample.xyz.com/api/mycall',
    headers: {
        'Content-Type': 'application/x-www-form-urlencoded'
    },
    type: "POST", /* or type:"GET" or type:"PUT" */
    dataType: "json",
    data: {
    },
    success: function (result) {
        console.log(result);
    },
    error: function () {
        console.log("error");
    }
});

หมายเหตุ:หากคุณกำลังมองหาเนื้อหาที่ดาวน์โหลดจากเว็บไซต์ของบุคคลที่สามแล้วนี้จะไม่ช่วยให้คุณ คุณสามารถลองรหัสต่อไปนี้ แต่ไม่ใช่ JavaScript

System.Net.WebClient wc = new System.Net.WebClient();
string str = wc.DownloadString("http://mysite.microsoft.sample.xyz.com/api/mycall");

การกำหนดค่านี้แก้ไขข้อผิดพลาดเดียวกันใน Wordpress ที่ Azure Services ขอบคุณ
Andre Mesquita

9
ฉันขอแนะนำให้ใช้ค่าต้นทางเฉพาะเพื่อหลีกเลี่ยงคำขอจากโดเมนภายนอก ตัวอย่างเช่นแทนที่จะ*ใช้https://www.myotherdomain.com
pechar


8

การใช้ข้อ จำกัด ธ เป็นคุณลักษณะการรักษาความปลอดภัยที่กำหนดโดยเซิร์ฟเวอร์และดำเนินการโดยเบราว์เซอร์

เบราว์เซอร์ดูที่นโยบาย CORS ของเซิร์ฟเวอร์และให้ความเคารพ

อย่างไรก็ตามเครื่องมือบุรุษไปรษณีย์ไม่ได้กังวลเกี่ยวกับนโยบาย CORS ของเซิร์ฟเวอร์

นั่นคือสาเหตุที่ข้อผิดพลาด CORS ปรากฏในเบราว์เซอร์ แต่ไม่ใช่ในบุรุษไปรษณีย์


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

7

ในการตรวจสอบด้านล่างว่าเป็น API ฉันใช้http://example.comแทนhttp: // myApiUrl / เข้าสู่ระบบจากคำถามของคุณเพราะอันแรกใช้ได้

ฉันคิดว่าหน้าของคุณอยู่ในhttp: //my-site.local: 8088

สาเหตุที่คุณเห็นผลลัพธ์ต่างกันคือบุรุษไปรษณีย์:

  • ส่วนหัวชุดHost=example.com(API ของคุณ)
  • ไม่ได้ตั้งค่าส่วนหัว Origin

นี้จะคล้ายกับวิธีที่เบราว์เซอร์ของการส่งคำขอเมื่อสถานที่และ API มีโดเมนเดียวกัน (เบราว์เซอร์ยังตั้งค่ารายการส่วนหัวReferer=http://my-site.local:8088แต่ผมไม่เห็นมันใน Postman) เมื่อไม่ได้ตั้งค่าOriginส่วนหัวโดยปกติเซิร์ฟเวอร์อนุญาตการร้องขอดังกล่าวตามค่าเริ่มต้น

ป้อนคำอธิบายภาพที่นี่

วิธีนี้เป็นวิธีมาตรฐานวิธีการที่บุรุษไปรษณีย์ส่งคำขอ แต่เบราว์เซอร์ส่งคำขอแตกต่างกันเมื่อไซต์และ API ของคุณมีโดเมนที่แตกต่างกันจากนั้นCORSจะเกิดขึ้นและเบราว์เซอร์จะดำเนินการโดยอัตโนมัติ:

  • ตั้งค่าส่วนหัวHost=example.com(ของคุณเป็น API)
  • ชุดส่วนหัวOrigin=http://my-site.local:8088(เว็บไซต์ของคุณ)

(ส่วนหัวRefererมีค่าเหมือนกันOrigin) และตอนนี้ในแท็บคอนโซลและเครือข่ายของ Chrome คุณจะเห็น:

ป้อนคำอธิบายภาพที่นี่

ป้อนคำอธิบายภาพที่นี่

เมื่อคุณมีHost != Originนี้คือ ธ และเมื่อเซิร์ฟเวอร์ตรวจพบการร้องขอดังกล่าวก็มักจะบล็อกได้โดยเริ่มต้นที่

Origin=nullถูกตั้งค่าเมื่อคุณเปิดเนื้อหา HTML จากไดเรกทอรีท้องถิ่นและมันจะส่งคำขอ สถานการณ์เดียวกันคือเมื่อคุณส่งคำขอภายใน<iframe>เช่นในตัวอย่างด้านล่าง (แต่ที่นี่Hostส่วนหัวไม่ได้ตั้งค่าทั้งหมด) - โดยทั่วไปข้อมูลจำเพาะ HTML ทุกที่บอกว่าต้นกำเนิดทึบแสงคุณสามารถแปลOrigin=nullได้ ข้อมูลเพิ่มเติมเกี่ยวกับเรื่องนี้คุณสามารถหาได้ที่นี่

fetch('http://example.com/api', {method: 'POST'});
Look on chrome-console > network tab

หากคุณไม่ได้ใช้ง่ายล ธ ขอมักเบราว์เซอร์โดยอัตโนมัตินอกจากนี้ยังส่ง OPTIONS ขอก่อนที่จะส่งคำขอหลัก - ข้อมูลเพิ่มเติมที่นี่ ตัวอย่างด้านล่างแสดง:

fetch('http://example.com/api', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json'}
});
Look in chrome-console -> network tab to 'api' request.
This is the OPTIONS request (the server does not allow sending a POST request)

คุณสามารถเปลี่ยนการกำหนดค่าเซิร์ฟเวอร์ของคุณเพื่อให้การร้องขอ CORS

นี่คือการกำหนดค่าตัวอย่างซึ่งเปิดCORS บน nginx (ไฟล์ nginx.conf) - ระวังให้มากด้วยการตั้งค่าalways/"$http_origin"สำหรับ nginx และ"*"Apache - นี่จะเป็นการปิดกั้น CORS จากโดเมนใด ๆ

นี่คือการกำหนดค่าตัวอย่างซึ่งเปิดCORS บน Apache (ไฟล์. htaccess)


2

พบข้อผิดพลาดเดียวกันในกรณีการใช้งานที่แตกต่างกัน

ใช้ตัวพิมพ์:ในโครเมี่ยมเมื่อพยายามเรียกจุดสิ้นสุดSpring REST เป็นมุม

ป้อนคำอธิบายรูปภาพที่นี่

โซลูชัน:เพิ่มคำอธิบายประกอบ@CrossOrigin ("*")ที่ด้านบนของคลาสตัวควบคุมที่เกี่ยวข้อง

ป้อนคำอธิบายรูปภาพที่นี่


ฉันใช้ localhost แทน * เพื่อความปลอดภัย
neo7bf

-1

หากคุณใช้. NET เป็นชั้นกลางให้ตรวจสอบแอตทริบิวต์เส้นทางอย่างชัดเจนตัวอย่างเช่น

ฉันมีปัญหาเมื่อมันเป็นเช่นนี้

[Route("something/{somethingLong: long}")] //Space.

แก้ไขโดยสิ่งนี้

[Route("something/{somethingLong:long}")] //No space

-1

สำหรับโครงการ. NET Core Web API เท่านั้นให้เพิ่มการเปลี่ยนแปลงต่อไปนี้:

  1. เพิ่มรหัสต่อไปนี้หลังจากservices.AddMvc()บรรทัดในConfigureServices()วิธีการของไฟล์ Startup.cs:
services.AddCors(allowsites=>{allowsites.AddPolicy("AllowOrigin", options => options.AllowAnyOrigin());
            });
  1. เพิ่มรหัสต่อไปนี้หลังจากapp.UseMvc()บรรทัดในConfigure()วิธีการของไฟล์ Startup.cs:
app.UseCors(options => options.AllowAnyOrigin());
  1. เปิดคอนโทรลเลอร์ที่คุณต้องการเข้าถึงภายนอกโดเมนและเพิ่มแอ็ตทริบิวต์ต่อไปนี้ที่ระดับคอนโทรลเลอร์:
[EnableCors("AllowOrigin")]
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.