尝试从REST API获取数据时,请求的资源上不存在“Access Control Allow Origin”标头

我正在尝试从HP Alm的REST API获取一些数据。它与一个小的curl脚本配合得很好——我得到了我的数据

现在,使用JavaScript、fetch和ES6(或多或少)这样做似乎是一个更大的问题。我一直收到以下错误消息:

无法加载获取API。对飞行前请求的响应不正确
通过访问控制检查:未显示“访问控制允许原点”标题
在请求的资源上显示。起源’http://127.0.0.1:3000”“是吗
因此不允许访问。响应的HTTP状态代码为501。
如果不透明响应满足您的需要,请将请求的模式设置为
“无cors”以获取禁用cors的资源

我理解这是因为我试图从本地主机中获取数据,解决方案应该使用CORS。现在我想我真的做到了,但不知怎么的,它要么忽略了我在标题中写的内容,要么问题出在其他地方

那么,是否存在实施问题?我做错了吗?很遗憾,我无法检查服务器日志。我真的有点困在这里了

函数performSignIn(){
let headers=新的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));
获取(登录){
//模式:“无cors”,
凭据:“包括”,
方法:“POST”,
标题:标题
})
.then(response=>response.json())
.then(json=>console.log(json))
.catch(错误=>console.log('授权失败:'+错误消息));
}

我用的是铬。我也尝试过使用Chrome CORS插件,但随后我收到另一条错误消息:

响应中“Access Control Allow Origin”标头的值
当请求的凭据模式为时,不能为通配符“*”
“包括”。起源’http://127.0.0.1:3000因此,”不允许”
通道由发起的请求的凭据模式
XMLHttpRequest由withCredentials属性控制

这个答案涵盖了很多方面,因此分为三个部分:

  • 如何使用CORS代理解决“无访问控制允许源站标头”问题
  • 如何避免CORS飞行前
  • 如何解决“访问控制允许源标题不能是通配符”的问题

如何使用CORS代理来避免“无访问控制允许源站标头”问题

如果您不控制前端代码向其发送请求的服务器,而该服务器的响应问题只是缺少必要的Access control Allow Origin头,那么您仍然可以通过CORS代理发出请求来完成工作

您可以使用源代码轻松运行自己的代理https://github.com/Rob–W/cors-anywhere/.
您还可以使用5个命令,在2-3分钟内轻松地将自己的代理部署到Heroku:

git克隆https://github.com/Rob--W/cors-anywhere.git
cd-cors随处可见/
npm安装
赫罗库创造
git推送heroku主机

在运行这些命令之后,您将在运行自己的CORS Anywhere服务器,例如,https://cryptic-headland-94862.herokuapp.com/

现在,将代理的URL作为请求URL的前缀:

https://cryptic-headland-94862.herokuapp.com/https://example.com

将代理URL添加为前缀会导致通过代理发出请求,这:

  1. 将请求转发到https://example.com
  2. https://example.com
  3. 访问控制允许原点标题添加到响应中
  4. 将带有添加的头的响应传递回请求的前端代码

然后浏览器允许前端代码访问响应,因为带有访问控制允许原点的响应是浏览器看到的

即使请求触发浏览器执行CORS飞行前选项请求,这也会起作用,因为在这种情况下,代理还会发送飞行前成功所需的访问控制允许标头访问控制允许方法标头


如何避免CORS飞行前检查

问题中的代码会触发CORS预飞行,因为它会发送授权标题

https://developer.mozilla.org/docs/Web/HTTP/Access_control_CORS#Preflighted_requests

即使没有它,Content-Type:application/json头也会触发预飞行

“飞行前”的意思是:在浏览器尝试问题代码中的POST之前,它首先向服务器发送OPTIONS请求,确定服务器是否选择接收具有授权内容类型的跨源POST:application/json标题

它与一个小的curl脚本配合得很好——我得到了我的数据

要使用curl进行正确测试,必须模拟浏览器发送的飞行前选项

curl-i-X选项-H”;来源:http://127.0.0.1:3000" \
-H'访问控制请求方法:POST'\
-H'访问控制请求头:内容类型,授权'\
&引用;https://the.sign_in.url"

…带有https://the.sign_in.url替换为您实际登录的URL

浏览器需要从该选项请求得到的响应必须具有如下标题:

访问控制允许原点:http://127.0.0.1:3000
访问控制允许方法:POST
访问控制允许标头:内容类型、授权

如果选项响应不包含这些标题,浏览器将立即停止,并且从不尝试发送POST请求。此外,响应的HTTP状态代码必须是2xx,通常为200或204。如果是任何其他状态代码,浏览器将立即停止

问题中的服务器用501状态代码响应选项请求,这显然意味着它试图表明它没有实现对选项请求的支持。在这种情况下,其他服务器通常使用405“不允许使用方法”状态代码进行响应

因此,如果服务器以405或501或200或204以外的任何方式响应该选项请求,或者如果服务器没有以这些必要的响应头响应,则您将永远无法从前端JavaScript代码直接向该服务器发出POST请求

避免触发问题案例飞行前准备的方法是:

  • 如果服务器不需要授权请求标头,而是依赖于POST请求正文中嵌入的身份验证数据或作为查询参数
  • 如果服务器不要求POST主体具有内容类型:application/json媒体类型,而是将POST主体接受为application/x-www-form-urlencoded,并带有名为json(或任何值为json数据的参数)

如何修复“访问控制允许源标题不能是通配符”问题

我收到另一条错误消息:

响应中“访问控制允许原点”标题的值
当请求的凭据模式为时,不能是通配符“*”
“包括”。来源“http://127.0.0.1:3000因此,不允许使用“
访问。由发起的请求的凭据模式
XMLHttpRequest由withCredentials属性控制。

对于具有凭据的请求,如果access Control Allow Origin头的值为*,浏览器将不允许前端JavaScript代码访问响应。相反,这种情况下的值必须与前端代码的来源完全匹配,http://127.0.0.1:3000

请参阅MDN HTTP访问控制(CORS)文章中的认证请求和通配符

如果您控制要向其发送请求的服务器,处理这种情况的一种常见方法是将服务器配置为获取Origin请求头的值,并将其回送/反映到访问控制允许Origin响应头的值中;e、 例如,使用nginx:

添加头访问控制允许源代码$http\u源代码

但这只是一个例子;其他(web)服务器系统也有类似的方法来回显原始值


我用的是铬。我也尝试过使用ChromeCors插件

Chrome CORS插件显然只是简单地将访问控制允许源代码:头插入到浏览器看到的响应中。如果插件更智能,那么它将把伪Access Control Allow Originresponse头的值设置为前端JavaScript代码的实际来源,http://127.0.0.1:3000

因此,避免使用该插件,即使是用于测试。这只是分散注意力。要测试在没有浏览器过滤的情况下从服务器得到的响应,最好使用上面提到的curl-H


至于前端JavaScri

发表评论