POST succeeds on server but results in CORS error

2019-01-20 12:41发布

I do an HTTP POST request to the microsoft login to get an access token to use with the mail API, the request succeeds but the code goes to the error clause of my code.

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)
  });
}

The browser console shows this: XMLHttpRequest cannot load https://login.microsoftonline.com/common/oauth2/v2.0/token. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:4200' is therefore not allowed access. zone.js:2019 XHR failed loading: POST "https://login.microsoftonline.com/common/oauth2/v2.0/token". outlook.service.ts:96 The error is = Response with status: 0 for URL: null

here's a screenshot to show it better Console error log

Now the real problem is that my request succeeds as shown below: Browsers' network tab

and the response shows my access token. So why cannot I get it from code? Why does it go the error-clause.

2条回答
戒情不戒烟
2楼-- · 2019-01-20 12:44

You already tagged your post correctly with "cors". Modern browsers does not allow accessing endpoints across domains, unless the endpoint sends cors-headers which allows you to access it.

If you check your network tab, there should be an OPTIONS-request to https://login.microsoftonline.com/common/oauth2/v2.0/token. This s called he preflight-request, which checks for Access-Control-Allow-Origin and Access-Control-Allow-Methods headers. Access-Control-Allow-Origin must contain your domain or *, and Control-Allow-Methods must contain POST or *.

I'm not familiar with the office apis, but i think there must be a way to configure your app as an valid endpoint. Perhaps this post will help you: https://msdn.microsoft.com/en-us/office/office365/howto/create-web-apps-using-cors-to-access-files-in-office-365

查看更多
虎瘦雄心在
3楼-- · 2019-01-20 12:57

What you’re seeing is expected behavior when sending a cross-origin POST to a server that doesn’t include the Access-Control-Allow-Origin response header in its response.

Specifically, as long as your cross-origin request has no characteristics that will cause your browser to do a preflight OPTIONS request before doing your POST request (which your request doesn’t) then the POST request will succeed on the server side—but, because the response from the server to that POST request doesn’t include the Access-Control-Allow-Origin response header, your browser blocks your frontend code from being able to actually see the response the server sends.

However, if you open browser devtools you can still see the response there. But just because the browser received the response and you can see it in devtools, it doesn’t mean the browser will expose the response to your code. It’ll only expose it when it has Access-Control-Allow-Origin.


That all may seem counter-intuitive but it all makes sense if you remember that the browser is the only point at which cross-origin restrictions are enforced. Servers don’t block cross-origin requests.

When the server you’re sending that POST request to receives the request, it doesn’t check the origin to decide whether to respond. The server just accepts the POST request and processes it and then sends a response. But then the browser blocks your code from access to that response.

But it’s also important to remember that the browser doesn’t block your code from sending that POST request cross-origin. Browsers only block cross-origin requests from being sent when the requests have qualities (like special headers) that trigger the browser to do a preflight.

So since your POST request isn’t one that triggers a preflight, the browser sends it and it succeeds.

For the sake of comparison, consider what happens for cross-origin GET requests. In that case too, as long at the GET request isn’t one that triggers a preflight, the browser doesn’t refuse to send it cross-origin. Instead, the browser sends the request to the server, regardless. And the server receives that GET request and sends a response.

It’s only when that response comes back to the browser that something different happens—because again, in that case, if the response doesn’t include the Access-Control-Allow-Origin response header, then your browser won’t allow your frontend JavaScript code to access it.

But obviously since the entire point of making a GET request is to do something with the response, then in that case if your code can’t access the response, that’s a hard, total failure—in contrast to the case of the POST request, where the request body does actually still get posted as expected, but you just don’t have a way for your code to check the response to see if the request succeeded.

查看更多
登录 后发表回答