为什么我的http://localhost CORS源不工作?

我被这个CORS问题困住了,即使我用适当的头设置了服务器(nginx/node.js)。

我可以看到在Chrome网络窗格->响应头:

Access-Control-Allow-Origin:http://localhost

这应该能奏效。

下面是我现在用来测试的代码:

var xhr = new XMLHttpRequest();
xhr.onload = function() {
console.log('xhr loaded');
};
xhr.open('GET', 'http://stackoverflow.com/');
xhr.send();

我得到

XMLHttpRequest无法加载http://stackoverflow.com/。Access-Control-Allow-Origin不允许Origin http://localhost

我怀疑这是客户端脚本的问题,而不是服务器配置…

559713 次浏览

Chrome 不支持本地主机的CORS请求(2010年打开的bug, 2014年标记为WontFix)。

为了解决这个问题,你可以使用像localho.st这样的域(就像localhost一样指向127.0.0.1),或者用--disable-web-security标志启动chrome(假设你只是在测试)。

真正的问题是,如果我们为所有请求设置-Allow- (OPTIONS &POST), Chrome将取消它。 下面的代码为我工作与POST到LocalHost与Chrome

<?php
if (isset($_SERVER['HTTP_ORIGIN'])) {
//header("Access-Control-Allow-Origin: {$_SERVER['HTTP_ORIGIN']}");
header("Access-Control-Allow-Origin: *");
header('Access-Control-Allow-Credentials: true');
header("Access-Control-Allow-Methods: GET, POST, OPTIONS");
}
if ($_SERVER['REQUEST_METHOD'] == 'OPTIONS') {
if (isset($_SERVER['HTTP_ACCESS_CONTROL_REQUEST_METHOD']))
header("Access-Control-Allow-Methods: GET, POST, OPTIONS");
if (isset($_SERVER['HTTP_ACCESS_CONTROL_REQUEST_HEADERS']))
header("Access-Control-Allow-Headers:{$_SERVER['HTTP_ACCESS_CONTROL_REQUEST_HEADERS']}");


exit(0);
}
?>

根据@Beau的回答,Chrome不支持本地主机CORS请求,在这个方向上不太可能有任何变化。

我使用允许-控制-允许-起源:* Chrome扩展来解决这个问题。扩展将为CORS添加必要的HTTP头:

Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: "GET, PUT, POST, DELETE, HEAD, OPTIONS"
Access-Control-Expose-Headers: <you can add values here>

源代码发布在Github上

注意,默认情况下扩展过滤所有url。这可能会破坏一些网站(例如:Dropbox)。我用下面的URL过滤器将其更改为仅过滤本地主机 URL

*://localhost:*/*

Chrome将使用来自localhost源的CORS发出请求。这不是Chrome的问题。

你不能加载http://stackoverflow.com的原因是Access-Control-Allow-Origin头文件不允许你的localhost来源。

我决定不碰报头,而是在服务器端进行重定向,这就像一个魅力。

下面的例子是针对Angular的当前版本(目前是9),也可能是其他使用webpacks DevServer的框架。但我认为同样的原则也适用于其他后端。

所以我在文件proxy.conf.json中使用以下配置:

{
"/api": {
"target": "http://localhost:3000",
"pathRewrite": {"^/api" : ""},
"secure": false
}
}

在Angular I中,使用这样的配置:

$ ng serve -o --proxy-config=proxy.conf.json

我更喜欢在serve命令中使用代理,但你也可以把这个配置放在angular.json中,像这样:

"architect": {
"serve": {
"builder": "@angular-devkit/build-angular:dev-server",
"options": {
"browserTarget": "your-application-name:build",
"proxyConfig": "src/proxy.conf.json"
},

参见:

https://www.techiediaries.com/fix-cors-with-angular-cli-proxy-configuration/

https://webpack.js.org/configuration/dev-server/#devserverproxy

这些扩展都不适合我,所以我安装了一个简单的本地代理。在我的例子中https://www.npmjs.com/package/local-cors-proxy 这是一个2分钟的设置:

(来自他们的网站)

npm install -g local-cors-proxy

API端点,我们想请求有CORS问题: https://www.yourdomain.ie/movies/list < / p >

开始代理:lcp --proxyUrl https://www.yourdomain.ie

然后在你的客户端代码中,新的API端点: http://localhost:8010/proxy/movies/list < / p >

这对我来说很有吸引力:你的应用程序调用代理,代理调用服务器。零CORS问题。

解决方案是安装一个扩展,以提升Chrome的块,例如:

Access Control-Allow-Origin - Unblock (https://add0n.com/access-control.html?version=0.1.5&type=install)。

同意!应该在服务器端启用CORS以彻底解决问题。然而……

对我来说,情况是:

我非常想用客户端提供的REST API在本地测试我的前端(React/Angular/VUE)代码,而不能访问服务器配置。

只是为了测试

在尝试了上面所有的步骤都没有工作后,我被迫在chrome上禁用网络安全和站点隔离试验,并指定用户数据目录(尝试跳过这个,没有工作)。

对于Windows

cd C:\Program Files\Google\Chrome\Application

禁用web安全和站点隔离试验

chrome.exe  --disable-site-isolation-trials --disable-web-security --user-data-dir="PATH_TO_PROJECT_DIRECTORY"

这终于起作用了!希望这能有所帮助!

我想我的解决办法可能是最简单的。在我的开发机器上,我在我的hosts文件中添加了一个类似http://myfakedomain.notarealtld的假域,并将其设置为127.0.0.1。然后我更改了服务器的CORS配置(在我的例子中是S3桶)以允许该域。这样我就可以在localhost上使用Chrome,它工作得很好。

确保您的CORS配置考虑到整个主机名与端口,即。http://myfakedomain.notarealtld:3000

您可以轻松地在Linux、Mac和Windows上修改主机文件。

Chrome确实允许本地主机上的CORS,我让它与AWS API网关/lambda一起工作。在发送http请求时,查看开发人员工具中的network选项卡非常有用。我的问题是我的lambda函数没有处理preflight OPTIONS请求,只有POST和GET。我通过接受OPTIONS请求解决了这个问题,并确保从我的API返回以下头:

  • Access-Control-Allow-Origin: '*'(或网站域名)
  • Access-Control-Allow-Methods: 'POST, GET, OPTIONS'
    • 这是飞行前的响应,告诉chrome,我们现在可以发送一个POST/GET请求
  • <李> Access-Control-Allow-Headers:“内容类型”
    • 不确定这是否是必要的,但它告诉chrome,请求可以包括一个内容类型头

需要注意的重要一点是浏览器会发送两组报头。

  1. OPTIONS头
    • access-control-request-method: 'POST'(或任何你正在请求的http方法)
    • 来源:“http://localhost:3000”(网站域名)
    • 推荐人:“http://localhost:3000/”(我相信这是完整的网站路径)
    • sec-fetch-mode:“歌珥”
    • sec-fetch-site:“跨站点”

如果请求1的响应是200码并且响应头包含: 'access-control-allow-methods': 'POST'(或请求中的access-control-request-method),

  1. 实际请求,例如:POST报头,其中包括
    • 内容类型:“application / json”
    • 产地:同上
    • 推荐人:同上

还有更多的标题,但我认为这些是最重要的。

你可以在没有任何安全绕过的情况下使用**CSRF **解决这个可怕的问题 在Github链接中找到关于CSRF的文章 https://github.com/adamchainz/django-cors-headers#csrf-integration < / p >