POST在服务器上成功但在浏览器中导致CORS错误

时间:2017-05-26 08:24:51

标签: angular http typescript cors

我对微软登录进行HTTP POST请求以获取与邮件API一起使用的访问令牌,请求成功但代码转到我的代码的错误子句。

requestAccessToken(code: string)
{
console.log("request access token");
if (code) {
  var headers = new Headers();
  headers.append("Content-Type", 'application/x-www-form-urlencoded');
  headers.append('Accept', 'application/json');
  var requestoptions = new RequestOptions({
    headers: headers
  });
  var body = `grant_type=authorization_code&
              redirect_uri=http://localhost:4200&
              code=`+ code + `&
              client_id=4e[................]5ab&
              client_secret=CE[..............]BC`;

  this.http.post("https://login.microsoftonline.com/common/oauth2/v2.0/token", body, requestoptions).map((res: Response) =>
  {
    console.log("response given");
    const data = res.json();
  }).subscribe( (data) => {
     console.log("The data is = " + data); 
  }, error => { 
    console.log("The error is = " + error)
  });
}

浏览器控制台显示: XMLHttpRequest无法加载https://login.microsoftonline.com/common/oauth2/v2.0/token。 No' Access-Control-Allow-Origin'标头出现在请求的资源上。起源' http://localhost:4200'因此不允许访问。 zone.js:2019 XHR加载失败:POST" https://login.microsoftonline.com/common/oauth2/v2.0/token"。 outlook.service.ts:96错误是=状态响应:URL为0:null

这里有一个屏幕截图,可以更好地展示它 Console error log

现在真正的问题是我的请求成功,如下所示: Browsers' network tab

并且响应显示了我的访问令牌。那么为什么我不能从代码中获取它呢?为什么它会出现错误条款。

2 个答案:

答案 0 :(得分:13)

当您将跨域POST发送到其响应中不包含Access-Control-Allow-Origin响应标头的服务器时,您所看到的是预期的行为。

具体来说,只要您的跨域请求没有导致浏览器在执行POST请求(您的请求没有请求)之前执行preflight OPTIONS request的特征,那么{{ 1}}请求将在服务器端成功 - 但是,因为服务器对该POST请求的响应不包含POST响应头,所以您的浏览器阻止您的前端代码能够实际上看到服务器发送的响应。

但是,如果您打开浏览器devtools,您仍然可以在那里看到响应。但仅仅因为浏览器收到了响应并且您可以在devtools中看到它,并不意味着浏览器会将响应暴露给您的代码。只有在Access-Control-Allow-Origin时才会公开它。

这一切似乎都是违反直觉的,但如果你记得浏览器是强制执行跨源限制的唯一点,那一切都是有道理的。服务器不会阻止跨源请求。

当您发送Access-Control-Allow-Origin请求的服务器收到请求时,它不会检查来源以决定是否响应。服务器只接受POST请求并处理它,然后发送响应。但是,浏览器会阻止您的代码访问该响应。

但同样重要的是要记住,浏览器不会阻止发送 POST请求跨域的代码。当请求具有触发浏览器执行preflight的质量(如特殊标头)时,浏览器仅阻止发送跨源请求。

因此,由于您的POST请求不是触发预检的请求,因此浏览器会发送该请求并且成功。

为了进行比较,请考虑跨源POST请求会发生什么。在这种情况下,只要GET请求不是触发预检的请求,浏览器就不会拒绝发送它。相反,浏览器将请求发送到服务器,无论如何。服务器收到GET请求并发送响应。

只有当该响应返回到浏览器时才会发生不同的事情 - 因为在这种情况下,如果响应不包含GET响应标头,那么您的浏览器将不允许您的前端用于访问它的JavaScript代码。

但很明显,因为发出Access-Control-Allow-Origin请求的全部内容都是对响应做了一些事情,那么在这种情况下,如果你的代码无法访问响应,那就是一个很难的,完全失败的 - 与GET请求的情况,请求正文实际上仍按预期发布,但您只是没有办法让代码检查响应以查看请求是否成功。

答案 1 :(得分:1)

您已使用“cors”正确标记了帖子。现代浏览器不允许跨域访问端点,除非端点发送允许您访问它的cors-headers。

如果您检查网络标签,则应向https://login.microsoftonline.com/common/oauth2/v2.0/token提出OPTIONS请求。这称为preflight-request,它检查Access-Control-Allow-Origin和Access-Control-Allow-Methods标头。 Access-Control-Allow-Origin必须包含您的域或*,而Control-Allow-Methods必须包含POST或*。

我不熟悉办公室api,但我认为必须有一种方法可以将您的应用配置为有效的端点。也许这篇文章可以帮到你:https://msdn.microsoft.com/en-us/office/office365/howto/create-web-apps-using-cors-to-access-files-in-office-365