我正在尝试从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插件,但是随后出现另一条错误消息:
响应中“ Access-Control-Allow-Origin”标头的值
当请求的凭据模式为时,不得为通配符'*'
'包括'。因此,不允许来源'http://127.0.0.1:3000'
访问。发起的请求的凭据模式
XMLHttpRequest由withCredentials属性控制。
最佳答案
该答案涉及很多领域,因此分为三个部分:
如何使用CORS代理来解决“无访问权限-允许-来源标头”问题
如何避免CORS飞行前
如何解决“ Access-Control-Allow-Origin标头一定不能为通配符”的问题
如何使用CORS代理来解决“无访问权限-允许-来源标头”问题
如果您不控制服务器,则您的前端JavaScript代码正在向其发送请求,并且该服务器的响应问题仅在于缺少必需的Access-Control-Allow-Origin
标头,您仍然可以使工作正常进行-通过CORS代理请求。为了展示它是如何工作的,首先这里是一些不使用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?"))
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前缀)会导致请求通过该代理发出,然后:
将请求转发到
https://example.com
。接收来自
https://example.com
的响应。将
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服务器,例如,在https://cryptic-headland-94862.herokuapp.com/上运行。因此,与其为您的请求URL加上
https://cors-anywhere.herokuapp.com
前缀,不如为您自己的实例的URL前缀;例如https://cryptic-headland-94862.herokuapp.com/https://example.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
标头。如何避免CORS飞行前
问题中的代码会触发CORS预检-因为它发送了
Authorization
标头。https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS#Preflighted_requests
即使没有,
Content-Type: application/json
标头也将触发预检。“预检”的含义是:在浏览器尝试问题代码中的
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"
…将
https://the.sign_in.url
替换为您实际的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
响应中不包含这些标头,则浏览器将在那里停止,甚至从不尝试发送POST
请求。另外,响应的HTTP状态代码必须为2xx(通常为200或204)。如果是其他任何状态代码,浏览器将在那里停止。问题中的服务器正在用501状态代码响应
OPTIONS
请求,这显然意味着它试图表明它未实现对OPTIONS
请求的支持。在这种情况下,其他服务器通常会以405“不允许使用方法”状态代码进行响应。因此,如果服务器使用405或501或200或204以外的任何值响应该
POST
请求,或者如果没有响应,则永远无法从前端JavaScript代码直接向该服务器发出OPTIONS
请求用那些必要的响应头来响应。避免触发该案件的预检的方法是:
如果服务器不需要
Authorization
请求标头,而是(例如)依赖于POST
请求正文中嵌入的身份验证数据或作为查询参数如果服务器不要求
POST
主体具有Content-Type: application/json
媒体类型,而是将POST
主体作为application/x-www-form-urlencoded
接受名为json
(或其他任何参数)的参数,其值是JSON数据如何解决“ Access-Control-Allow-Origin标头一定不能为通配符”的问题
我收到另一条错误消息:
响应中“ Access-Control-Allow-Origin”标头的值
当请求的凭据模式为时,不得为通配符'*'
'包括'。因此,不允许来源'http://127.0.0.1:3000'
访问。发起的请求的凭据模式
XMLHttpRequest由withCredentials属性控制。
对于包含凭据的请求,如果
Access-Control-Allow-Origin
响应标头的值为*
,浏览器将不允许您的前端JavaScript代码访问响应。相反,在这种情况下,该值必须与您的前端代码的来源http://127.0.0.1:3000
完全匹配。请参阅MDN HTTP访问控制(CORS)文章中的Credentialed requests and wildcards。
如果您控制要向其发送请求的服务器,则处理这种情况的一种常用方法是将服务器配置为采用
Origin
请求标头的值,并将其回显/反射回Access-Control-Allow-Origin
响应头。例如,使用nginx: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
的实际来源。因此,即使进行测试,也请避免使用该插件。这只是分心。如果您想测试从服务器获得的响应,而无需浏览器对其进行过滤,则最好使用上述的
curl -H
。至于问题中
fetch(…)
请求的前端JavaScript代码:headers.append('Access-Control-Allow-Origin', 'http://localhost:3000');
headers.append('Access-Control-Allow-Credentials', 'true');
删除这些行。
Access-Control-Allow-*
标头是响应标头。您永远不想在请求中发送它们。唯一的影响就是触发浏览器进行预检。
关于javascript - 尝试从REST API获取数据时,请求的资源上没有“Access-Control-Allow-Origin” header ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48046637/