我正在尝试从HP Alm的REST API中获取一些数据。它与一个小的curl脚本一起使用时效果很好-我得到了数据。
现在使用JavaScript进行操作,获取和ES6(或多或少)似乎是一个更大的问题。我不断收到此错误消息:
提取API无法加载。对预检请求的响应未通过访问控制检查:请求的资源上不存在“ Access-Control-Allow- Origin”标头。因此,不允许访问源’ http://127.0.0.1:3000 ‘。响应的HTTP状态代码为501。如果不透明的响应满足您的需求,请将请求的模式设置为“ no-cors”,以在禁用CORS的情况下获取资源。
我知道这是因为我试图从本地主机中获取数据,并且解决方案应使用CORS。现在我以为我确实做到了,但是以某种方式它要么忽略了我在标题中写的内容,要么是其他问题?
那么,是否存在实施问题?我做错了吗?我无法检查服务器日志。我真的有点卡在这里。
function performSignIn() { let headers = new Headers(); headers.append('Content-Type', 'application/json'); headers.append('Accept', 'application/json'); headers.append('Access-Control-Allow-Origin', 'http://localhost:3000'); headers.append('Access-Control-Allow-Credentials', 'true'); headers.append('GET', 'POST', 'OPTIONS'); headers.append('Authorization', 'Basic ' + base64.encode(username + ":" + password)); fetch(sign_in, { //mode: 'no-cors', credentials: 'include', method: 'POST', headers: headers }) .then(response => response.json()) .then(json => console.log(json)) .catch(error => console.log('Authorization failed : ' + error.message)); }
我正在使用Chrome。我也尝试使用该Chrome CORS插件,但是随后出现另一条错误消息:
当请求的凭据模式为“ include”时,响应中“ Access-Control-Allow-Origin”标头的值不得为通配符“ *”。因此,不允许访问源’ http://127.0.0.1:3000 ‘。XMLHttpRequest发起的请求的凭据模式由withCredentials属性控制。
该答案涉及很多领域,因此分为三个部分:
如何使用CORS代理来解决 “无访问权限-允许-来源标头” 问题
如果您不控制服务器,则您的前端JavaScript代码正在向其发送请求,而该服务器的响应问题仅在于缺少必要的Access-Control-Allow- Origin标头,那么您仍然可以使事情顺利进行-通过通过CORS代理。为了展示它是如何工作的,首先这里是一些不使用CORS代理的代码:
Access-Control-Allow- Origin
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?"))
造成该catch区块被打的原因是,浏览器阻止该代码访问从返回的响应https://example.com。而浏览器这样做的原因是,响应缺少Access- Control-Allow-Origin响应头。
catch
https://example.com
Access- Control-Allow-Origin
现在,这是完全相同的示例,只是在其中添加了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?"))
注意:如果在尝试https://cors- anywhere.herokuapp.com时关闭或不可用,请参见下文,了解如何在2-3分钟内在Heroku上部署自己的CORS Anywhere服务器。
上面的第二个代码段可以成功访问响应,因为采用请求URL并将其更改为https://cors- anywhere.herokuapp.com/https://example.com(只需在其前面加上代理URL)即可请求通过该代理取得,然后:
Access-Control-Allow-Origin
然后,浏览器允许前端代码访问响应,因为带有Access-Control-Allow-Origin响应标头的响应就是浏览器看到的内容。
您可以使用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服务器。因此,不要在您的请求URL前面加上https://cors- anywhere.herokuapp.com,而是在您自己的实例的URL 前面加上前缀。
https://cors- anywhere.herokuapp.com
因此,如果您尝试使用https://cors-anywhere.herokuapp.com时发现它已关闭 (有时会 关闭 ),则考虑获取一个Heroku帐户(如果您尚未使用)并拿2或花费3分钟完成上述步骤,以在Heroku上部署您自己的CORS Anywhere服务器。
无论您是运行自己的网站还是使用https://cors-anywhere.herokuapp.com或其他开放式代理,即使该请求触发了浏览器执行CORS预检OPTIONS请求,该解决方案仍然可以使用- 因为在这种情况下,代理还会发回使预检成功所需的Access-Control-Allow-Headers和Access-Control-Allow- Methods标头。
OPTIONS
Access-Control-Allow-Headers
Access-Control-Allow- Methods
如何避免CORS飞行前
问题中的代码由于发送了Authorization标头而触发了CORS预检。
Authorization
https://developer.mozilla.org/zh- CN/docs/Web/HTTP/Access_control_CORS#Preflighted_requests
即使没有这些,Content-Type: application/json标题也将触发预检。
Content-Type: application/json
“预检”的含义是:在浏览器尝试输入POST问题代码之前,它将首先向OPTIONS服务器发送请求- 确定服务器是否选择接收POST包含Authorization和Content-Type: application/json标头的跨域。
POST
它与一个小的curl脚本一起使用时效果很好-我得到了数据。
要使用进行正确的测试curl,您需要模拟OPTIONS浏览器发送的预检请求:
curl
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"
… https://the.sign_in.url替换为您的实际sign_in网址。
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
如果OPTIONS响应中不包含这些标头,则浏览器将在那里停止,甚至从不尝试发送POST请求。另外,响应的HTTP状态代码必须为2xx,通常为200或204。如果是其他任何状态代码,浏览器将在此处停止。
问题中的服务器正在OPTIONS使用501状态代码来响应请求,这显然意味着它试图表明它未实现对OPTIONS请求的支持。在这种情况下,其他服务器通常会以405“不允许使用方法”状态代码进行响应。
因此POST,如果服务器OPTIONS使用405或501或200或204以外的任何其他值响应该请求,或者如果未响应必要的响应,则永远无法从前端JavaScript代码直接向该服务器发出请求响应头。
避免触发该案件的预检的方法是:
application/x-www-form-urlencoded
json
如何解决 “ Access-Control-Allow-Origin标头一定不能为通配符”的 问题
我收到另一条错误消息: 当请求的凭据模式为“ include”时,响应中“ Access-Control-Allow-Origin”标头的值不得为通配符“ *”。因此,不允许访问源’ http://127.0.0.1:3000 ‘。XMLHttpRequest发起的请求的凭据模式由withCredentials属性控制。
我收到另一条错误消息:
对于包含凭据的请求,如果Access-Control-Allow- Origin响应标头的值为,浏览器将不允许您的前端JavaScript代码访问响应*。相反,在这种情况下,值必须与前端代码的来源完全匹配http://127.0.0.1:3000。
*
http://127.0.0.1:3000
如果控制要向其发送请求的服务器,则处理这种情况的一种常用方法是将服务器配置为采用Origin请求标头的值,并将其回显/反射回Access-Control-Allow-Origin响应标头的值。例如,使用nginx:
Origin
add_header Access-Control-Allow-Origin $http_origin
但这只是一个例子。其他(网络)服务器系统提供了类似的方法来回显原始值。
我正在使用Chrome。我也尝试过使用Chrome CORS插件
Chrome CORS插件显然只是将Access-Control-Allow-Origin: *标头注入浏览器看到的响应中。如果该插件更聪明,它将采取的措施是将该假Access-Control-Allow- Origin响应标头的值设置为您的前端JavaScript代码的实际来源http://127.0.0.1:3000。
Access-Control-Allow-Origin: *
因此,即使进行测试,也请避免使用该插件。这只是分心。如果您想测试从服务器获得的响应,而没有浏览器对其进行过滤,则最好使用curl -H上述方法。
curl -H
至于fetch(…)问题中请求的前端JavaScript代码:
fetch(…)
headers.append('Access-Control-Allow-Origin', 'http://localhost:3000'); headers.append('Access-Control-Allow-Credentials', 'true');
删除这些行。该Access-Control-Allow-*头是 响应 头。您永远不想在请求中发送它们。唯一的效果就是触发浏览器进行预检。
Access-Control-Allow-*