เหตุใดรหัส JavaScript ของฉันจึงได้รับข้อผิดพลาด“ No 'Access-Control-Allow-Origin' อยู่ในทรัพยากรที่ร้องขอ” ในขณะที่บุรุษไปรษณีย์ไม่ได้รับ
หมายเหตุ Mod : คำถามนี้เกี่ยวกับสาเหตุที่บุรุษไปรษณีย์ไม่อยู่ภายใต้ข้อ จำกัด CORS ในลักษณะเดียวกับ XMLHttpRequest คำถามนี้ไม่เกี่ยวกับวิธีแก้ไขข้อผิดพลาด "No" Access-Control-Allow-Origin "... "
กรุณาหยุดโพสต์ :
- การกำหนดค่า CORS สำหรับทุกภาษา / กรอบภายใต้ดวงอาทิตย์ แทนที่จะหา / คำถามกรอบของภาษาที่เกี่ยวข้องของคุณ
- บริการของบุคคลที่สามที่อนุญาตให้มีการร้องขอเพื่อหลีกเลี่ยง CORS
- ตัวเลือกบรรทัดคำสั่งสำหรับปิด CORS สำหรับเบราว์เซอร์ต่างๆ
ฉันกำลังพยายามที่จะทำการอนุญาตใช้งาน JavaScriptโดยการเชื่อมต่อไปยังสงบ APIในตัวขวด อย่างไรก็ตามเมื่อฉันร้องขอฉันได้รับข้อผิดพลาดต่อไปนี้:
XMLHttpRequest ไม่สามารถโหลดhttp: // myApiUrl / เข้าสู่ระบบ ไม่มีส่วนหัว "Access-Control-Allow-Origin" ในทรัพยากรที่ร้องขอ Origin 'null' จึงไม่อนุญาตให้เข้าถึง
ฉันรู้ว่า API หรือทรัพยากรระยะไกลต้องตั้งค่าส่วนหัว แต่ทำไมมันไม่ทำงานเมื่อฉันทำคำขอผ่านทางส่วนขยายของ Chrome Postman ?
นี่คือรหัสคำขอ:
$.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);
});
คำตอบ
ถ้าฉันเข้าใจถูกต้องคุณกำลังทำXMLHttpRequestไปยังโดเมนอื่นที่ไม่ใช่เพจของคุณ ดังนั้นเบราว์เซอร์จึงปิดกั้นเนื่องจากโดยปกติจะอนุญาตให้มีการร้องขอในต้นทางเดียวกันด้วยเหตุผลด้านความปลอดภัย คุณต้องทำสิ่งที่แตกต่างออกไปเมื่อคุณต้องการทำคำขอข้ามโดเมน กวดวิชาเกี่ยวกับวิธีการเพื่อให้บรรลุว่าคือการใช้ล ธ
เมื่อคุณใช้บุรุษไปรษณีย์นโยบายนี้จะไม่ถูก จำกัด อ้างจากCross-Origin XMLHttpRequest :
หน้าเว็บปกติสามารถใช้อ็อบเจ็กต์ XMLHttpRequest เพื่อส่งและรับข้อมูลจากเซิร์ฟเวอร์ระยะไกลได้ แต่จะถูก จำกัด โดยนโยบายต้นทางเดียวกัน ส่วนขยายไม่ จำกัด ส่วนขยายสามารถพูดคุยกับเซิร์ฟเวอร์ระยะไกลนอกจุดเริ่มต้นได้ตราบใดที่ส่วนขยายนั้นขอสิทธิ์ข้ามแหล่งที่มาก่อน
คำเตือน:การใช้
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
จากนั้นรวมคอร์ขวดในแอปพลิเคชันของคุณ
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!"
เนื่องจาก
$ .ajax ({type: "POST" - เรียกOPTIONS
$ .post ( - เรียกPOST
ทั้งสองอย่างแตกต่างกัน บุรุษไปรษณีย์เรียก "POST" อย่างถูกต้อง แต่เมื่อเราเรียกมันจะเป็น "OPTIONS"
สำหรับบริการเว็บ C # - 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");
ในการตรวจสอบด้านล่างในฐานะ API ฉันใช้http://example.comแทนhttp: // myApiUrl / loginจากคำถามของคุณเพราะอันแรกใช้ได้
ฉันคิดว่าหน้าของคุณอยู่ใน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 จากโลคัลไดเร็กทอรีและจะส่งคำขอ สถานการณ์เดียวกันคือเมื่อคุณส่งคำขอภายใน an <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 จากโดเมนใดก็ได้
location ~ ^/index\.php(/|$) {
...
add_header 'Access-Control-Allow-Origin' "$http_origin" always;
add_header 'Access-Control-Allow-Credentials' 'true' always;
if ($request_method = OPTIONS) {
add_header 'Access-Control-Allow-Origin' "$http_origin"; # DO NOT remove THIS LINES (doubled with outside 'if' above)
add_header 'Access-Control-Allow-Credentials' 'true';
add_header 'Access-Control-Max-Age' 1728000; # cache preflight value for 20 days
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
add_header 'Access-Control-Allow-Headers' 'My-First-Header,My-Second-Header,Authorization,Content-Type,Accept,Origin';
add_header 'Content-Length' 0;
add_header 'Content-Type' 'text/plain charset=UTF-8';
return 204;
}
}
นี่คือตัวอย่างการกำหนดค่าที่เปิดCORS บน Apache (ไฟล์. htaccess)
# ------------------------------------------------------------------------------
# | Cross-domain Ajax requests |
# ------------------------------------------------------------------------------
# Enable cross-origin Ajax requests.
# http://code.google.com/p/html5security/wiki/CrossOriginRequestSecurity
# http://enable-cors.org/
# <IfModule mod_headers.c>
# Header set Access-Control-Allow-Origin "*"
# </IfModule>
# Header set Header set Access-Control-Allow-Origin "*"
# Header always set Access-Control-Allow-Credentials "true"
Access-Control-Allow-Origin "http://your-page.com:80"
Header always set Access-Control-Allow-Methods "POST, GET, OPTIONS, DELETE, PUT"
Header always set Access-Control-Allow-Headers "My-First-Header,My-Second-Header,Authorization, content-type, csrf-token"
การใช้ข้อ จำกัด ธ เป็นคุณลักษณะการรักษาความปลอดภัยที่กำหนดโดยเซิร์ฟเวอร์และดำเนินการโดยเบราว์เซอร์
เบราว์เซอร์ดูนโยบาย CORS ของเซิร์ฟเวอร์และเคารพ
อย่างไรก็ตามเครื่องมือ Postman ไม่ได้กังวลเกี่ยวกับนโยบาย CORS ของเซิร์ฟเวอร์
นั่นคือสาเหตุที่ข้อผิดพลาด CORS ปรากฏในเบราว์เซอร์ แต่ไม่ใช่ในบุรุษไปรษณีย์
พบข้อผิดพลาดเดียวกันในกรณีการใช้งานที่แตกต่างกัน
Use Case:ใน chrome เมื่อพยายามเรียก Spring REST end point ในเชิงมุม
วิธีแก้ไข:เพิ่มคำอธิบายประกอบ@CrossOrigin ("*")ที่ด้านบนของคลาสคอนโทรลเลอร์ตามลำดับ
หากคุณต้องการที่จะข้ามข้อ จำกัด ว่าเมื่อดึงเนื้อหาที่มีการดึงข้อมูล API หรือ XMLHttpRequest ใน javascript, คุณสามารถใช้พร็อกซีเซิร์ฟเวอร์เพื่อที่จะกำหนดส่วนหัวไปAccess-Control-Allow-Origin
*
const express = require('express');
const request = require('request');
const app = express();
app.use((req, res, next) => {
res.header('Access-Control-Allow-Origin', '*');
next();
});
app.get('/fetch', (req, res) => {
request(
{ url: req.query.url },
(error, response, body) => {
if (error || response.statusCode !== 200) {
return res.status(500).send('error');
}
res.send(body);
}
)
});
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => console.log(`listening on ${PORT}`));
ด้านบนคือโค้ดตัวอย่าง (ต้องมีโหนด Js) ซึ่งสามารถทำหน้าที่เป็นพร็อกซีเซิร์ฟเวอร์ได้ ตัวอย่างเช่น: หากฉันต้องการดึงข้อมูลhttps://www.google.com
ตามปกติข้อผิดพลาด CORS จะถูกส่งไป แต่ตอนนี้เนื่องจากคำขอถูกส่งผ่านพร็อกซีเซิร์ฟเวอร์ที่โฮสต์ในเครื่องที่พอร์ต 3000 พร็อกซีเซิร์ฟเวอร์จะเพิ่มAccess-Control-Allow-Origin
ส่วนหัวในการตอบกลับและจะไม่มีปัญหาใด ๆ
ส่งคำขอ GET ไปที่ http: // localhost: 3000 / fetch? url = Your URL here
แทนที่จะส่งคำขอไปยัง URl ที่คุณต้องการดึงข้อมูลโดยตรง
Your URL here
ย่อมาจาก URL ที่คุณต้องการดึงข้อมูลเช่น: https://www.google.com
สำหรับโครงการ. NET Core Web API เท่านั้นให้เพิ่มการเปลี่ยนแปลงต่อไปนี้:
- เพิ่มรหัสต่อไปนี้หลัง
services.AddMvc()
บรรทัดในConfigureServices()
วิธีการของไฟล์ Startup.cs:
services.AddCors(allowsites=>{allowsites.AddPolicy("AllowOrigin", options => options.AllowAnyOrigin());
});
- เพิ่มรหัสต่อไปนี้หลัง
app.UseMvc()
บรรทัดในConfigure()
วิธีการของไฟล์ Startup.cs:
app.UseCors(options => options.AllowAnyOrigin());
- เปิดตัวควบคุมที่คุณต้องการเข้าถึงภายนอกโดเมนและเพิ่มแอตทริบิวต์ต่อไปนี้ที่ระดับคอนโทรลเลอร์:
[EnableCors("AllowOrigin")]