This answer covers a lot of ground, so it's divided into three parts:
(该答案涉及很多领域,因此分为三个部分:)
How to use a CORS proxy to get around “No Access-Control-Allow-Origin header” problems
(如何使用CORS代理来解决“无访问控制-允许-来源标头”问题)
If you don't control the server your frontend JavaScript code is sending a request to, and the problem with the response from that server is just the lack of the necessary Access-Control-Allow-Origin
header, you can still get things to work—by making the request through a CORS proxy.
(如果您不控制服务器,您的前端JavaScript代码正在向其发送请求,并且该服务器的响应问题仅在于缺少必要的Access-Control-Allow-Origin
标头,那么您仍然可以使事情正常进行-通过CORS代理发出请求。)
To show how that works, first here's some code that doesn't use a CORS proxy: (为了展示它是如何工作的,首先这里是一些不使用CORS代理的代码:)
const url = "https://example.com"; // site that doesn't send Access-Control-* fetch(url) .then(response => response.text()) .then(contents => console.log(contents)) .catch(() => console.log("Can't access " + url + " response. Blocked by browser?"))
The reason the catch
block gets hit there is, the browser prevents that code from accessing the response which comes back from https://example.com
.
(导致catch
块被击中的原因是,浏览器阻止该代码访问来自https://example.com
的响应。)
And the reason the browser does that is, the response lacks the Access-Control-Allow-Origin
response header. (而浏览器这样做的原因是,该响应缺少Access-Control-Allow-Origin
响应标头。)
Now, here's exactly the same example but just with a CORS proxy added in:
(现在,这是完全相同的示例,只是在其中添加了CORS代理:)
const proxyurl = "https://cors-anywhere.herokuapp.com/"; const url = "https://example.com"; // site that doesn't send Access-Control-* fetch(proxyurl + url) // https://cors-anywhere.herokuapp.com/https://example.com .then(response => response.text()) .then(contents => console.log(contents)) .catch(() => console.log("Can't access " + url + " response. Blocked by browser?"))
Note: If https://cors-anywhere.herokuapp.com is down or unavailable when you try it, then see below for how to deploy your own CORS Anywhere server at Heroku in just 2-3 minutes.
(注意:如果在尝试https://cors-anywhere.herokuapp.com时关闭或不可用,请参见下文,了解如何在2-3分钟内在Heroku上部署自己的CORS Anywhere服务器。)
The second code snippet above can access the response successfully because taking the request URL and changing it to https://cors-anywhere.herokuapp.com/https://example.com —by just prefixing it with the proxy URL—causes the request to get made through that proxy, which then:
(上面的第二个代码段可以成功访问响应,因为采用请求URL并将其更改为https://cors-anywhere.herokuapp.com/https://example.com(仅在其前面加上代理URL)会导致请求通过该代理取得,然后:)
- Forwards the request to
https://example.com
. (将请求转发到https://example.com
。)
- Receives the response from
https://example.com
. (从https://example.com
接收响应。)
- Adds the
Access-Control-Allow-Origin
header to the response. (将Access-Control-Allow-Origin
标头添加到响应中。)
- Passes that response, with that added header, back to the requesting frontend code.
(将带有添加的标头的响应传递回请求的前端代码。)
The browser then allows the frontend code to access the response, because that response with the Access-Control-Allow-Origin
response header is what the browser sees.
(然后,浏览器允许前端代码访问响应,因为带有Access-Control-Allow-Origin
响应标头的响应就是浏览器看到的内容。)
You can easily run your own proxy using code from https://github.com/Rob--W/cors-anywhere/ .
(您可以使用https://github.com/Rob--W/cors-anywhere/中的代码轻松运行自己的代理。)
You can also easily deploy your own proxy to Heroku in literally just 2-3 minutes, with 5 commands:
(您还可以使用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
After running those commands, you'll end up with your own CORS Anywhere server running at, eg, https://cryptic-headland-94862.herokuapp.com/ .
(运行完这些命令后,您将最终在以下位置运行自己的CORS Anywhere服务器,例如https://cryptic-headland-94862.herokuapp.com/ 。)
So then rather than prefixing your request URL with https://cors-anywhere.herokuapp.com
, prefix it instead with the URL for your own instance; (因此,不要在请求URL前面加上https://cors-anywhere.herokuapp.com
,而是在您自己的实例的URL前面加上前缀;)
eg, https://cryptic-headland-94862.herokuapp.com/https://example.com . (例如https://cryptic-headland-94862.herokuapp.com/https://example.com 。)
So if when you go to try to use https://cors-anywhere.herokuapp.com, you find it's down (which it sometimes will be), then consider getting a Heroku account (if you don't already) and take 2 or 3 minutes to do the steps above to deploy your own CORS Anywhere server on Heroku.
(因此,如果您尝试使用https://cors-anywhere.herokuapp.com时发现它已关闭 (有时会出现故障 ),那么可以考虑获取一个Heroku帐户(如果您尚未使用)并拿2或花费3分钟完成上述步骤,以在Heroku上部署您自己的CORS Anywhere服务器。)
Regardless, whether you run your own or use https://cors-anywhere.herokuapp.com or other open proxy, this solution will work even if the request is one that triggers browsers to do a CORS preflight OPTIONS
request—because in that case, the proxy also sends back the Access-Control-Allow-Headers
and Access-Control-Allow-Methods
headers needed to make the preflight successful.
(无论您是运行自己的网站还是使用https://cors-anywhere.herokuapp.com或其他开放式代理,即使该请求是触发浏览器执行CORS预检OPTIONS
请求的请求,该解决方案都将起作用-因为在这种情况下,代理还会发回使预检成功所需的Access-Control-Allow-Headers
和Access-Control-Allow-Methods
头。)
How to avoid the CORS preflight
(如何避免CORS飞行前)
The code in the question triggers a CORS preflight—since it sends an Authorization
header.
(问题中的代码会触发CORS预检-因为它发送了Authorization
标头。)
https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS#Preflighted_requests
(https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Access_control_CORS#Preflighted_requests)
Even without that, the Content-Type: application/json
header would also trigger the preflight.
(即使没有这些Content-Type: application/json
, Content-Type: application/json
标头也将触发预检。)
What “preflight” means: before the browser tries the POST
in the code in the question, it'll first send an OPTIONS
request to the server — to determine if the server is opting-in to receiving a cross-origin POST
that includes the Authorization
and Content-Type: application/json
headers.
(“预检”的含义是:在浏览器尝试问题代码中的POST
之前,它将首先向服务器发送OPTIONS
请求-确定服务器是否选择接收包含以下内容的跨域POST
: Authorization
和Content-Type: application/json
标头。)
It works pretty well with a small curl script - I get my data.
(它与一个小的curl脚本一起使用时效果很好-我得到了数据。)
To properly test with curl
, you need to emulate the preflight OPTIONS
request the browser sends:
(为了正确地使用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"
…with https://the.sign_in.url
replaced by whatever your actual sign_in
URL is.
(…将https://the.sign_in.url
替换为您实际的sign_in
URL。)
The response the browser needs to see from that OPTIONS
request must include headers like this:
(浏览器需要从该OPTIONS
请求中看到的响应必须包括以下标头:)
Access-Control-Allow-Origin: http://127.0.0.1:3000
Access-Control-Allow-Methods: POST
Access-Control-Allow-Headers: Content-Type, Authorization
If the OPTIONS
response doesn't include those headers, then the browser will stop right there and never even attempt to send the POST
request.
(如果OPTIONS
响应不包含这些标头,则浏览器将在那里停止,甚至从不尝试发送POST
请求。)
Also, the HTTP status code for the response must be a 2xx—typically 200 or 204. If it's any other status code, the browser will stop right there. (另外,响应的HTTP状态代码必须为2xx,通常为200或204。如果是其他任何