1

As I understand, a pre-flight request is sent by the browser if any of the following conditions is false (source: https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#Simple_requests):

  • Request method is GET, HEAD or POST.
  • Custom headers are not set.
  • Content-Type header value is either application/x-www-form-urlencoded, multipart/form-data or text/plain.

I have a web app which sends a GET request to a server on a different origin. Since I have to send cookies to the server, the property withCredentials is set to true. The header Content-Type is set to application/json. For this request, the browser does not trigger a pre-flight request, but it should because the third condition is false. What could be the reason behind this? Does it have anything to do with the insignificance of Content-Type header for a GET request (since there is no request body)?

EDIT: Adding request code:

configObject = {
  'withCredentials': true,
  headers: {
    'Content-Type': 'application/json'
  }
};

function getRequest(url, dict) {
  $http.get(url, Object.assign({}, configObject)).success(function(result) {
    // on success
  }).error(function(err) {
    // on error
  });
  // return
}
sideshowbarker
  • 81,827
  • 26
  • 193
  • 197
Shubham
  • 780
  • 3
  • 13
  • 32
  • You’ll need to post your request code if you want insight from others here — because it sounds like your actual code’s not doing what’s described in the question. If the code is initiating a cross-origin request and the code making the request is actually setting the Content-Type header to application/json, then that absolutely will trigger the browser to perform a preflight. Always. – sideshowbarker Dec 24 '18 at 12:44
  • @sideshowbarker I doubt the header is being actually set. When I inspect the request (in the Network tab of the browser), this header is not present in the request headers. Added the code now. – Shubham Dec 24 '18 at 12:51
  • 1
    Yeah, I’m not sure why the code is using 'Object.assign({}, configObject)' as the second parameter to that .get call rather than just 'configObject', but I guess you might want to try it with just '$http.get(url, configObject)'. And if that doesn’t cause the header to be set as expected then I really have no idea. Personally, I’d recommend instead just using the standard fetch method… – sideshowbarker Dec 24 '18 at 13:33
  • @sideshowbarker That was indeed the problem. Angular was removing this header in absence of a request body. Can you post this as an answer? – Shubham Dec 26 '18 at 07:51

1 Answers1

2

If your frontend code is initiating a cross-origin request and the code making the request actually sets the Content-Type header to application/json, then that’ll absolutely trigger the browser to do a preflight. Always.

So that means, in the case in the question, the reason the browser isn’t getting triggered to do a preflight is that the header isn’t actually getting added to the request the browser ends up sending.

But the particular case described in the question is… odd — because it’s trying to add a Content-Type header to a GET request, and the GET request in the question (like pretty much all other GET requests) doesn’t have a request body.

And so what the cause comes down to in this case is that Angular, for $http calls, automatically does something arguably kind of smart (if unexpected): In the absence of a request body, it removes the Content-Type header from the request — which makes some good sense, because if there’s no request body, there’s no need to have a header specifying its media type.

See the accepted answer at Angular, content type is not being sent with $http for confirmation of that.

And so, if for some reason you really need to include the Content-Type header in a request having no request body, then the solution is either to not use Angular’s $http at all — and instead use, say, the standard Fetch API, which will allow you to include the Content-Type even for requests lacking a request body — or else (in case you also have some requirement to use Angular’s $http) to pass in an empty request body as part of the $http request (by adding data: '' to the request).

sideshowbarker
  • 81,827
  • 26
  • 193
  • 197