Mod note:这个问题是关于为什么 XMLHttpRequest/fetch/etc.浏览器上的受相同访问策略限制(您会收到提及 CORB 或 CORS 的错误),而 Postman 则不受此限制。这个问题不是关于如何修复“No 'Access-Control-Allow-Origin'...”错误。这是关于它们发生的原因。
请停止发帖:日光下每种语言/框架的 CORS 配置。而是找到您的相关语言/框架的问题。允许请求绕过 CORS 的第 3 方服务 用于关闭各种浏览器的 CORS 的命令行选项
我正在尝试通过连接到 RESTful API 内置 Flask 来使用 JavaScript 进行授权。但是,当我提出请求时,我收到以下错误:
XMLHttpRequest 无法加载 http://myApiUrl/login。请求的资源上不存在“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。因此浏览器会阻止它,因为出于安全原因,它通常允许同一来源的请求。当您想要进行跨域请求时,您需要做一些不同的事情。 Using CORS 是关于如何实现这一目标的教程。
当您使用 Postman 时,它们不受此政策的限制。引自Cross-Origin XMLHttpRequest:
常规网页可以使用 XMLHttpRequest 对象从远程服务器发送和接收数据,但它们受到同源策略的限制。扩展并没有那么有限。扩展程序可以与其源之外的远程服务器通信,只要它首先请求跨域权限。
警告:使用 Access-Control-Allow-Origin: * 会使您的 API/网站容易受到跨站请求伪造 (CSRF) 攻击。在使用此代码之前,请确保您了解风险。
如果您使用 PHP,解决起来非常简单。只需在处理请求的 PHP 页面的开头添加以下脚本:
<?php header('Access-Control-Allow-Origin: *'); ?>
如果您使用 Node-red,则必须通过取消注释以下行来允许 node-red/settings.js
文件中的 CORS:
// 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
然后在您的应用程序中包含 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!"
有关详细信息,您可以查看 Flask documentation。
因为 $.ajax({type: "POST" - 调用 OPTIONS $.post( - 调用 POST
两者是不同的。邮递员正确地调用“POST”,但当我们调用它时,它将是“OPTIONS”。
对于 C# 网络服务 - Web API
请在
<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。
注意:API 和您的页面具有不同的域!
您看到不同结果的原因是 Postman:
设置标头 Host=example.com (您的 API)
未设置标题来源
Postman 实际上根本不使用您的网站网址(您只需在 Postman 中输入您的 API 地址) - 他只向 API 发送请求,因此他假设网站与 API 具有相同的地址(浏览器不假设这一点)
这类似于站点和 API 具有相同域时浏览器发送请求的方式(浏览器也设置了标题项 Referer=http://my-site.local:8088
,但我在 Postman 中看不到它)。 当 Origin
标头未设置时,通常服务器默认允许此类请求。
https://i.stack.imgur.com/XLrRg.png
这是 Postman 发送请求的标准方式。但是,当您的网站和 API 具有不同的域时,浏览器会发送不同的请求,然后发生 CORS 并且浏览器会自动:
设置标题 Host=example.com (你的作为 API)
设置标题 Origin=http://my-site.local:8088 (您的站点)
(标头 Referer
与 Origin
具有相同的值)。现在在 Chrome 的 Console &网络 标签,您将看到:
https://i.stack.imgur.com/oZkcL.png
https://i.stack.imgur.com/8ITev.png
当您有 Host != Origin
时,这就是 CORS,并且当服务器检测到此类请求时,它通常默认阻止它。
Origin=null
在您从本地目录打开 HTML 内容并发送请求时设置。同样的情况是当您在 <iframe>
中发送请求时,就像在下面的代码段中一样(但这里根本没有设置 Host
标头)- 通常,在 HTML 规范中提到不透明来源的任何地方,您都可以将其翻译到 Origin=null
。有关这方面的更多信息,您可以找到 here。
fetch('http://example.com/api', {method: 'POST'});查看 chrome-console > 网络选项卡
如果您不使用简单的 CORS 请求,通常浏览器还会在发送主请求之前自动发送一个 OPTIONS 请求 - 更多信息是 here。下面的片段显示了它:
fetch('http://example.com/api', { method: 'POST', headers: { 'Content-Type': 'application/json'} });在 chrome-console -> 网络选项卡中查看“api”请求。这是 OPTIONS 请求(服务器不允许发送 POST 请求)
您可以更改服务器的配置以允许 CORS 请求。
这是一个示例配置,它打开 CORS on nginx(nginx.conf 文件) - 为 nginx 设置 always/"$http_origin"
和为 Apache 设置 "*"
时要非常小心 - 这将解除对任何域的 CORS 的阻止(在生产中而不是星星使用消耗你的api的具体页面地址)
location ~ ^/index\.php(/|$) { ... add_header 'Access-Control-Allow-Origin' "$http_origin" 总是; add_header 'Access-Control-Allow-Credentials' 'true' 总是; if ($request_method = OPTIONS) { add_header 'Access-Control-Allow-Origin' "$http_origin"; # 不要删除此行(与上面的外部“if”加倍) add_header 'Access-Control-Allow-Credentials' 'true'; add_header '访问控制-最大年龄' 1728000; # 缓存 20 天的预检值 add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS'; add_header 'Access-Control-Allow-Headers' '我的第一个标题,我的第二个标题,授权,内容类型,接受,来源'; add_header '内容长度' 0; add_header 'Content-Type' 'text/plain charset=UTF-8';返回204; } }
这是在 Apache 上打开 CORS 的示例配置(.htaccess 文件)
#------------------------------------------------ ----------------------------------------- # |跨域 Ajax 请求 | #------------------------------------------------ ----------------------------- # 启用跨域 Ajax 请求。 # http://code.google.com/p/html5security/wiki/CrossOriginRequestSecurity # http://enable-cors.org/ #
应用 CORS 限制是由服务器定义并由浏览器实现的安全功能。
浏览器查看服务器的 CORS 策略并尊重它。
但是,Postman 工具并不关心服务器的 CORS 策略。
这就是为什么 CORS 错误出现在浏览器中,而不是 Postman 中的原因。
您得到的错误是由于 CORS 标准造成的,该标准对 JavaScript 如何执行 ajax 请求设置了一些限制。
CORS 标准是在浏览器中实现的客户端标准。因此,阻止调用完成并生成错误消息的是浏览器,而不是服务器。
Postman 没有实现 CORS 限制,这就是为什么在从 Postman 发出相同调用时看不到相同错误的原因。
为什么 Postman 不实施 CORS? CORS 定义了与发起请求的页面的来源(URL 域)相关的限制。但在 Postman 中,请求并非来自具有 URL 的页面,因此 CORS 不适用。
解决方案和问题起源
您正在向不同的域创建 XMLHttpRequest,例如:
域一:some-domain.com 域二:some-different-domain.com
域名的这种差异触发了名为 SOP (Same-Origin Policy) 的 CORS (Cross-Origin Resource Sharing) 政策,该政策强制使用相同的域(因此 Origin) 在 Ajax、XMLHttpRequest 和其他 HTTP 请求中。
为什么当我通过 Chrome 扩展 Postman 发出请求时它会起作用?
客户端(大多数浏览器和开发工具)可以选择强制执行同源策略。
大多数浏览器都会执行同源策略以防止与 CSRF (Cross-Site Request Forgery) 攻击相关的问题。
Postman 作为开发工具选择不强制执行 SOP,而某些浏览器强制执行,这就是为什么您可以通过 Postman 发送无法使用浏览器通过 JS 使用 XMLHttpRequest 发送的请求。
用于浏览器测试目的:Windows - 运行:
chrome.exe --user-data-dir="C://Chrome dev session" --disable-web-security
如果您的网关超时太短并且您正在访问的资源的处理时间比超时时间长,您也可能会收到此错误。这可能是复杂的数据库查询等的情况。因此,上面的错误代码可以掩盖这个问题。只需检查错误代码是否为 504 而不是 404,如上面的 Kamils 回答或其他内容。如果是 504,那么增加网关超时可能会解决问题。
在我的情况下,可以通过在 IE 浏览器中禁用同源策略 (CORS) 来消除 CORS 错误,请参阅 How to disable same origin policy Internet Explorer。执行此操作后,日志中出现纯 504 错误。
要解决此问题,请在后端使用的 doGet()
或 doPost()
函数中编写这行代码
response.setHeader("Access-Control-Allow-Origin", "*");
代替 "*"
键入正在访问该网站的网站或 api url 端点。
您的 IP 未列入白名单,因此您收到此错误。要求后端人员将您正在访问的服务的 IP 列入白名单 https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Headers
“您可以做出的最快修复是安装 moesif CORS 扩展:https://chrome.google.com/webstore/detail/moesif-origin-cors-change/digfbfaphojjndkpccljibejjbppifbc/related?hl=en-US
安装后,在浏览器中单击它以激活扩展程序。确保图标的标签从“关闭”变为“打开”:
然后刷新您的应用程序,您的 API 请求现在应该可以工作了!”
不定期副业成功案例分享