这个答案涵盖了很多领域,所以它分为三个部分:
- 如何使用 CORS 代理避免“无访问控制-允许-源标头”问题
- 如何避免 CORS 印前检查
- 如何修复“访问控制-允许-源标头不得为通配符”问题
如何使用 CORS 代理避免“无访问控制-允许-源标头”问题
如果您不控制前端代码要向其发送请求的服务器,并且来自该服务器的响应的问题只是缺少必要的标头,则仍可以通过 CORS 代理发出请求来使事情正常工作。Access-Control-Allow-Origin
您可以使用 https://github.com/Rob--W/cors-anywhere/ 中的代码轻松运行自己的代理。
您还可以在短短2-3分钟内轻松地将自己的代理部署到Heroku,只需5个命令:
git clone https://github.com/Rob--W/cors-anywhere.git
cd cors-anywhere/
npm install
heroku create
git push heroku master
运行这些命令后,您最终将拥有自己的 CORS Anywhere 服务器,例如 ,.https://cryptic-headland-94862.herokuapp.com/
现在,在请求 URL 前面加上代理的 URL:
https://cryptic-headland-94862.herokuapp.com/https://example.com
将代理 URL 添加为前缀会导致请求通过代理发出,这:
- 将请求转发到 。
https://example.com
- 接收来自 的响应。
https://example.com
- 将标头添加到响应中。
Access-Control-Allow-Origin
- 将该响应(添加了该标头)传递回请求的前端代码。
然后,浏览器允许前端代码访问响应,因为带有响应标头的响应是浏览器看到的。Access-Control-Allow-Origin
即使请求是触发浏览器执行 CORS 预检请求的请求,这也有效,因为在这种情况下,代理还会发送使预检成功所需的 和 标头。OPTIONS
Access-Control-Allow-Headers
Access-Control-Allow-Methods
如何避免 CORS 印前检查
问题中的代码会触发 CORS 预检,因为它会发送标头。Authorization
https://developer.mozilla.org/docs/Web/HTTP/Access_control_CORS#Preflighted_requests
即使没有它,标头也会触发预检。Content-Type: application/json
“precheck”是什么意思:在浏览器尝试问题中的代码之前,它首先向服务器发送请求,以确定服务器是否选择接收具有和标头的跨源。POST
OPTIONS
POST
Authorization
Content-Type: application/json
它与一个小的curl脚本配合得很好 - 我得到我的数据。
要正确测试 ,您必须模拟浏览器发送的印前检查:curl
OPTIONS
curl -i -X OPTIONS -H "Origin: http://127.0.0.1:3000" \
-H 'Access-Control-Request-Method: POST' \
-H 'Access-Control-Request-Headers: Content-Type, Authorization' \
"https://the.sign_in.url"
...替换为您的实际URL。https://the.sign_in.url
sign_in
浏览器需要从该请求获得的响应必须具有如下标头:OPTIONS
Access-Control-Allow-Origin: http://127.0.0.1:3000
Access-Control-Allow-Methods: POST
Access-Control-Allow-Headers: Content-Type, Authorization
如果响应不包含这些标头,浏览器将在此处停止,并且永远不会尝试发送请求。此外,响应的 HTTP 状态代码必须是 2xx,通常为 200 或 204。如果是任何其他状态代码,浏览器将就在那里停止。OPTIONS
POST
问题中的服务器使用501状态代码响应请求,这显然意味着它试图表明它没有实现对请求的支持。在这种情况下,其他服务器通常使用 405“不允许的方法”状态代码进行响应。OPTIONS
OPTIONS
因此,如果服务器使用405或501或200或204以外的任何内容响应该请求,或者如果不使用这些必要的响应标头响应,则您将永远无法从前端JavaScript代码直接向该服务器发出请求。POST
OPTIONS
避免触发问题中案例的预检的方法是:
- 如果服务器不需要请求标头,而是依赖于请求正文中嵌入的身份验证数据或作为查询参数
Authorization
POST
- 如果服务器不要求正文具有媒体类型,而是接受正文,因为参数名为(或其他参数),其值为 JSON 数据
POST
Content-Type: application/json
POST
application/x-www-form-urlencoded
json
如何修复“访问控制-允许-源标头不得为通配符”问题
我收到另一条错误消息:
当请求的凭据模式为“include”时,响应中的“访问控制-允许-源”标头的值不得为通配符“*”。因此,不允许访问源“http://127.0.0.1:3000
”。由 XMLHttpRequest 发起的请求的凭据模式由 withCredentials 属性控制。
对于具有凭据的请求,如果标头的值为 ,则浏览器不会让您的前端 JavaScript 代码访问响应。相反,在这种情况下,值必须与前端代码的来源完全匹配。Access-Control-Allow-Origin
*
http://127.0.0.1:3000
请参阅 MDN HTTP 访问控制 (CORS) 一文中的凭据请求和通配符。
如果您控制要向其发送请求的服务器,则处理这种情况的常用方法是将服务器配置为获取请求标头的值,并将其回显/反射回响应标头的值;例如,使用nginx:Origin
Access-Control-Allow-Origin
add_header Access-Control-Allow-Origin $http_origin
但这只是一个例子;其他(Web)服务器系统具有类似的方法来回显源值。
我使用的是 Chrome。我还尝试使用Chrome CORS插件
Chrome CORS插件显然只是简单地将标头注入浏览器看到的响应中。如果插件更聪明,它将所做的是将假响应标头的值设置为前端JavaScript代码的实际来源。Access-Control-Allow-Origin: *
Access-Control-Allow-Origin
http://127.0.0.1:3000
因此,即使用于测试,也要避免使用该插件。这只是一种分心。要测试您从服务器获得的响应,而无需浏览器过滤它们,最好使用如上所述。curl -H
至于问题中请求的前端 JavaScript 代码:fetch(…)
headers.append('Access-Control-Allow-Origin', 'http://localhost:3000');
headers.append('Access-Control-Allow-Credentials', 'true');
删除这些行。标头是响应标头。您永远不想在请求中发送它们。这样做的唯一效果是触发浏览器进行预检。Access-Control-Allow-*