提问人:Mr Jedi 提问时间:11/18/2013 最后编辑:pizzaisdavidMr Jedi 更新时间:7/30/2023 访问量:6188526
为什么我的 JavaScript 代码收到“请求的资源上不存在'Access-Control-Allow-Origin'标头”错误,而 Postman 没有?
Why does my JavaScript code receive a "No 'Access-Control-Allow-Origin' header is present on the requested resource" error, while Postman does not?
问:
Mod 说明:这个问题是关于为什么浏览器上的 //etc. 受到相同访问策略限制(您收到提及 CORB 或 CORS 的错误),而 Postman 则不受限制。这个问题不是关于如何解决“没有'访问-控制-允许-起源'......”的问题。错误。这是关于它们发生的原因。
XMLHttpRequest
fetch
请停止发帖:
- 适用于每种语言/框架的 CORS 配置。相反,找到相关语言/框架的问题。
- 允许请求规避 CORS 的第三方服务
- 用于关闭各种浏览器的 CORS 的命令行选项
我正在尝试通过连接到 RESTful API 内置 Flask 来使用 JavaScript 进行授权。但是,当我提出请求时,出现以下错误:
XMLHttpRequest cannot load http://myApiUrl/login.
No 'Access-Control-Allow-Origin' header is present on the requested resource.
Origin 'null' is therefore not allowed access.
我知道 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。因此,浏览器阻止了它,因为出于安全原因,它通常允许同一来源的请求。当您想要执行跨域请求时,您需要执行一些不同的操作。
当您使用 Postman 时,它们不受此策略的限制。引自跨域 XMLHttpRequest:
常规网页可以使用 XMLHttpRequest 对象从远程服务器发送和接收数据,但它们受到同源策略的限制。扩展没有那么有限。扩展可以与其源之外的远程服务器通信,只要它首先请求跨域权限即可。
评论
警告:使用可以使您的 API/网站容易受到跨站请求伪造 (CSRF) 攻击。在使用此代码之前,请确保您了解风险。
Access-Control-Allow-Origin: *
如果您使用的是 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
然后,在应用程序中包含 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 文档。
评论
因为
$.ajax({type: “POST” - 调用 OPTIONS
$.post( - 调用 POST
两者都是不同的。Postman 正确地调用“POST”,但当我们调用它时,它将是“OPTIONS”。
对于 C# Web 服务 - 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。
注意:API 和您的页面具有不同的域!
您看到不同结果的原因是 Postman:
- set header(您的 API)
Host=example.com
- NOT 设置标头
Origin
- Postman 实际上根本不使用您的网站 url(您只在 Postman 中输入您的 API 地址) - 他只向 API 发送请求,因此他假设网站与 API 具有相同的地址(浏览器不假设这一点)
这类似于浏览器在站点和 API 具有相同域时发送请求的方式(浏览器也设置了标头项,但我在 Postman 中没有看到它)。当未设置 Origin
标头时,通常服务器默认允许此类请求。Referer=http://my-site.local:8088
这是 Postman 发送请求的标准方式。但是,当您的网站和 API 具有不同的域时,浏览器会以不同的方式发送请求,然后发生 CORS,浏览器会自动:
- 设置标头(作为 API)
Host=example.com
- 设置标头(您的网站)
Origin=http://my-site.local:8088
(标头的值与 相同。现在,在Chrome的“控制台和网络”选项卡中,您将看到:Referer
Origin
当您拥有 Host != Origin
时,这是 CORS,当服务器检测到此类请求时,它通常会默认阻止它。
Origin=null
当您从本地目录打开 HTML 内容并发送请求时设置。同样的情况是,当您在 中发送请求时,如下面的代码片段(但此处根本没有设置标头) - 一般来说,只要 HTML 规范说 opaque origin,您都可以将其转换为 .您可以在此处找到有关此内容的更多信息。<iframe>
Host
Origin=null
fetch('http://example.com/api', {method: 'POST'});
Look on chrome-console > network tab
如果您不使用简单的 CORS 请求,通常浏览器在发送主请求之前也会自动发送 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 请求。
这是一个在nginx(nginx.conf文件)上打开CORS的示例配置--在nginx和Apache的设置时要非常小心-这将从任何域中取消阻止CORS(在生产中,而不是星号使用使用你的具体页面广告,它消耗你的api)always/"$http_origin"
"*"
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;
}
}
下面是在 Apache 上打开 CORS 的示例配置(.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"
评论
If you are not seeing the same problem when using postman, this means that you are unknowingly not sending the same request via postman
应用 CORS 限制是由服务器定义并由浏览器实现的安全功能。
浏览器查看服务器的 CORS 策略并遵守它。
但是,Postman 工具不会为服务器的 CORS 策略而烦恼。
这就是为什么CORS错误出现在浏览器中,而不是Postman中的原因。
您遇到的错误是由于 CORS 标准造成的,该标准对 JavaScript 如何执行 ajax 请求设置了一些限制。
CORS 标准是在浏览器中实现的客户端标准。因此,阻止调用完成并生成错误消息的是浏览器,而不是服务器。
Postman 未实现 CORS 限制,这就是为什么在从 Postman 进行相同调用时看不到相同的错误。
为什么 Postman 不实现 CORS?CORS 定义了与发起请求的页面的源(URL 域)相关的限制。但在 Postman 中,请求不是来自具有 URL 的页面,因此 CORS 不适用。
评论
如果网关超时时间太短,并且所访问的资源的处理时间比超时长,则也可能收到此错误。对于复杂的数据库查询等,可能会出现这种情况。因此,上面的错误代码可以掩盖这个问题。只需检查错误代码是否是 504 而不是 Kamil 的答案中的 404 或其他内容。如果是 504,则增加网关超时可能会解决问题。
在我的情况下,可以通过在 Internet Explorer 浏览器中禁用同源策略 (CORS) 来消除 CORS 错误,请参阅如何禁用同源策略 Internet Explorer。这样做之后,日志中出现了纯 504 错误。
评论
解决方案和问题起源
您正在向不同的域发出 XMLHttpRequest,例如:
- 领域一:
some-domain.com
- 领域二:
some-different-domain.com
域名的这种差异触发了称为 SOP(同源策略)的 CORS(跨域资源共享)策略,该策略强制在 Ajax、XMLHttpRequest 和其他 HTTP 请求中使用相同的域(因此是 Origin)。
为什么当我通过 Chrome 扩展程序发出请求时它能正常工作 邮差?
客户端(大多数浏览器和开发工具)可以选择强制执行同源策略。
大多数浏览器都执行同源策略,以防止与CSRF(跨站点请求伪造)攻击相关的问题。
Postman 作为一种开发工具,选择不强制执行 SOP,而某些浏览器强制执行,这就是为什么您可以通过 Postman 发送请求,而您不能使用浏览器通过 JS 使用 XMLHttpRequest 发送请求。
出于浏览器测试目的:
Windows - 运行:
chrome.exe --user-data-dir="C://Chrome dev session" --disable-web-security
上面的命令将禁用 chrome 网络安全。因此,例如,如果您在本地项目上工作并在尝试发出请求时遇到 CORS 策略问题,则可以使用上述命令跳过此类错误。基本上,它将打开一个新的chrome会话。
评论
您的 IP 地址未列入白名单,因此您会收到此错误。 要求后端工作人员将您正在访问的服务的 IP 地址列入白名单。
Access-Control-Allow-Headers 访问控制允许标头
若要解决此问题,请在后端使用的 或 函数中编写此代码行doGet()
doPost()
response.setHeader("Access-Control-Allow-Origin", "*");
您可以输入访问网站的网站或 API URL 端点,否则它将是公开的。"*"
它通过在全球范围内应用这个中间件对我有用:
<?php
namespace App\Http\Middleware;
use Closure;
class Cors {
public function handle($request, Closure $next) {
return $next($request)
->header('Access-Control-Allow-Origin', '*')
->header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS')
->header('Access-Control-Allow-Headers', "Accept,authorization,Authorization, Content-Type");
}
}
评论
对我来说,我出于不同的原因遇到了这个问题,远程域已添加到源中,部署的应用程序运行良好,除了一个端点我遇到了这个问题:
Origin https://mai-frontend.vercel.app is not allowed by Access-Control-Allow-Origin. Status code: 500
和
Fetch API cannot load https://sciigo.herokuapp.com/recommendations/recommendationsByUser/8f1bb29e-8ce6-4df2-b138-ffe53650dbab due to access control checks.
我发现我的 Heroku 数据库表不包含本地表的所有列,更新 Heroku 数据库表后一切正常。
可以通过在服务器的 web.config 文件中添加以下脚本来允许 CORS。
<system.webServer>
<httpProtocol>
<customHeaders>
<add name="Access-Control-Allow-Origin" value="*" />
<add name="Access-Control-Allow-Methods" value="*" />
<add name="Access-Control-Allow-Headers" value="*" />
</customHeaders>
</httpProtocol>
</system.webServer>
如果您使用 Node.js (Express.js) 构建后端,请尝试使用npm i cors
....
const cors = require("cors");
.....
app.use(cors());
...
评论