David David - 29 days ago 11
HTTP Question

HTTP request from angular will send with method OPTIONS instead of POST

I'm trying to send some HTTP requests from my angular.js application to my server, but I need to solve some cors errors.

The HTTP request are equal to this sample:

functions.test = function(foo, bar) {
return $http({
method: 'POST',
url: api_endpoint + 'test',
headers: {
'foo': 'value',
'content-type': 'application/json'
},
data: {
bar:'value'
}
});
};


the first try end with some cors errors. So I've implement the following lines to my php server script:

header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: POST, GET, OPTIONS, DELETE, PUT');
header('Access-Control-Allow-Headers: X-Requested-With, Content-Type, Origin, Authorization, Accept, Client-Security-Token, Accept-Encoding, X-Auth-Token, content-type');


The first error is now eliminated.

Now the developer console (on chrome) show me the following errors:


angular.js:12011 OPTIONS http://localhost:8000/test (anonymous
function)

423ef03a:1 XMLHttpRequest cannot load
http://localhost:8000/test. Response for preflight has invalid HTTP
status code 400


and the network request looks like I expected (status 400 is also expected):

network request

I can't imagine how to solve the thing (and how to understand) why the request will send on localhost as OPTIONS and to remote servers as POST. Is there a solution how to fix this strange thing?

Answer

The OPTIONS request is so called pre-flight request, which is part of Cross-origin resource sharing (CORS). Browsers use it to check if the real request, which will follow in case of success, is allowed from the particular domain.

Browsers are sending the pre-flight requests in these cases:

  • custom HTTP headers like application/xml or application/json, etc., are used
  • the request method is other than GET, HEAD or POST and the POST method is of an another content type than application/x-www-form-urlencoded, multipart/form-data or text/plain

You need to make sure that the response to the pre-flight request has the following attributes:

  • successful HTTP status code, i.e. 200 OK
  • header Access-Control-Allow-Origin: * (* allows request from any domain, you can use any specific domain to restrict the access here of course)

From the other side, the server may refuse the CORS request simply by sending the response to the pre-flight request with the following attributes:

  • non-success HTTP code (i.e. other than 2XX)
  • success HTTP code (e.g. 200 OK), but without any CORS header (i.e. Access-Control-Allow-*)

So, in your case, the proper header is present, you just have to make sure the pre-flight response's HTTP status code is 200 OK.

See the documentation on Mozilla Developer Network or for example HTML5Rocks' CORS tutorial for details.