这个答案涉及很广,所以分为三个部分:
- 如何使用CORS代理解决大约“No Access-Control-Allow-Origin header”个问题
- 如何避免CORS飞行前
- 如何解决“Access-Control-Allow-Origin header must not be the wildcard”个问题
How to use a CORS proxy to avoid “No Access-Control-Allow-Origin header” problems
如果您无法控制前端代码向其发送请求的服务器,而该服务器的响应问题只是缺少必要的Access-Control-Allow-Origin
报头,那么您仍然可以通过CORS代理发出请求来完成工作.
您可以使用https://github.com/Rob--W/cors-anywhere/起的代码轻松运行自己的代理.
您还可以通过5条命令,在2-3分钟内轻松将自己的代理部署到Heroku:
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
头也会触发一次印前判断.
"飞行前"的意思是:在浏览器try 问题代码中的POST
之前,它首先向服务器发送OPTIONS
请求,以确定服务器是否 Select 接收包含Authorization
和Content-Type: application/json
个头的交叉源POST
.
它与一个小的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"
…用实际的sign_in
URL替换https://the.sign_in.url
.
浏览器需要的OPTIONS
个请求的响应必须具有如下标题:
Access-Control-Allow-Origin: http://127.0.0.1:3000
Access-Control-Allow-Methods: POST
Access-Control-Allow-Headers: Content-Type, Authorization
如果OPTIONS
响应不包含这些标题,浏览器将立即停止,永远不会try 发送POST
请求.此外,响应的HTTP状态代码必须是2xx,通常为200或204.如果是任何其他状态代码,浏览器将立即停止.
问题中的服务器用501状态代码响应OPTIONS
个请求,这显然意味着它试图表明它没有实现对OPTIONS
个请求的支持.在这种情况下,其他服务器通常会使用405"不允许使用方法"状态代码进行响应.
因此,如果服务器使用405或501或除200或204以外的任何值响应OPTIONS
请求,或者如果没有使用这些必要的响应头响应,您将永远无法从前端JavaScript代码直接向该服务器发出POST
个请求.
避免触发问题中 case 的印前判断的方法是:
- 如果服务器不需要
Authorization
请求头,而是依赖嵌入POST
请求主体中的身份验证数据或作为查询参数
- 如果服务器不要求
POST
body具有Content-Type: application/json
媒体类型,而是将POST
body接受为application/x-www-form-urlencoded
,并带有一个名为json
(或其他名称)的参数,该参数的值是JSON数据
如何解决“Access-Control-Allow-Origin header must not be the wildcard”个问题
我收到另一条错误消息:
The value of the 'Access-Control-Allow-Origin' header in the response
must not be the wildcard '*' when the request's credentials mode is
'include'. Origin 'http://127.0.0.1:3000
' is therefore not allowed
access. The credentials mode of requests initiated by the
XMLHttpRequest is controlled by the withCredentials attribute.
对于具有凭据的请求,如果Access-Control-Allow-Origin
标头的值为*
,浏览器将不会让您的前端JavaScript代码访问响应.相反,这种情况下的值必须与您的前端代码的来源http://127.0.0.1:3000
完全匹配.
请参阅MDN HTTP访问控制(CORS)文章中的Credentialed requests and wildcards.
如果您控制要向其发送请求的服务器,处理这种情况的常用方法是将服务器配置为采用Origin
请求标头的值,并将其 echo /反映到Access-Control-Allow-Origin
响应标头的值中;例如,使用nginx:
add_header Access-Control-Allow-Origin $http_origin
但这只是一个例子;其他(Web)服务器系统也有类似的 echo 原始值的方式.
我用的是Chrome.我也try 过使用Chrome CORS插件
Chrome CORS插件显然只是简单地在浏览器看到的响应中注入了Access-Control-Allow-Origin: *
个标题.如果插件更智能,那么它将把假Access-Control-Allow-Origin
响应头的值设置为前端JavaScript代码http://127.0.0.1:3000
的实际来源.
所以避免使用该插件,即使是用于测试.这只是分散注意力.要测试在没有浏览器过滤的情况下从服务器得到的响应,最好使用上面的curl -H
.
至于问题中fetch(…)
个请求的前端JavaScript代码:
headers.append('Access-Control-Allow-Origin', 'http://localhost:3000');
headers.append('Access-Control-Allow-Credentials', 'true');
go 掉那些线.Access-Control-Allow-*
个报头是response个报头.您永远不会想要向他们发送请求.这样做的唯一效果是触发浏览器执行印前判断.