16

AngularJS transforms my POST request into OPTIONS when I add Authorization header:

  $http({
    url: ApiEndpoint + 'logout',
    method: 'POST',
    headers: {
      'Content-Type': 'application/x-www-form-urlencoded',
      'Authorization': UserService.getApiKey()
    }
  })

I'm developpling a hybrid mobile application with Ionic that I test in browser, os it's a CORS request.

I have already seen this question. The proposed workaround is to change Content-Type that I did and it worked without Authorization. With Authorization header the request is changed again to OPTIONS method.

Can you propose client solution please because a have no control over server API.

Thank you.

VladRia
  • 1,475
  • 3
  • 20
  • 32
  • 3
    Preflight will be triggered in your case as setting 'Authorization' header will make your request *not simple* in MDN terms. The only allowed headers to be set manually to classify as *simple* are Accept, Accept-Language, Content-Language and Content-Type. Ref: https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS .Not sure whether you could avoid pre-flight, but you could cache it for a given time frame for requests. – Developer Aug 21 '16 at 17:31

3 Answers3

6

as Developer remarked, the CORS request will be preflighted unless it is a simple request.

Community
  • 1
  • 1
VladRia
  • 1,475
  • 3
  • 20
  • 32
6

As others have noted, what you are seeing are CORS preflight requests.

You can't avoid them if you want to set Authorization header, but there are some workarounds if you control the backend (or are willing to use proxy). More info: https://damon.ghost.io/killing-cors-preflight-requests-on-a-react-spa/

In short:

  • CORS preflight headers can be cached by browser (set Access-Control-Max-Age header to number of seconds the response should be cached)
  • authorization header can be moved to URL params (if this is a good idea or not is a whole other discussion)
  • you can send JSON without proper headers (again, not the best of ideas, but...)
  • if it fits your use case, the simplest solution is to use proxy and thus avoid cross-origin requests completely
johndodo
  • 17,247
  • 15
  • 96
  • 113
  • "CORS preflight headers can be cached" -- it would be nice if you added some explanation about how that is done. – Dave Nov 13 '20 at 17:05
  • Sure, done. (and I need to add some bogus text here so that this comment is at least 15 chars long) – johndodo Nov 14 '20 at 19:05
-2

To avoid preflight request, Just create your own controller and then, From the server code call the other origin REST service.

<pre>

public void doPost(HttpServletRequest request, HttpServletResponse response)
   throws IOException {
  String outputString = request.getParameter("data");  /*Refer the ajax data $.ajax({
         url:"callRestApi",
         type:'POST',
         data: { 
    "data":"data Value"
   },
         beforeSend: function (xhr) {
             xhr.setRequestHeader ("Authorization", "Basic " + btoa(uname + ":" + passwd));
         },
         success:function(){
          alert("Successfully created JSON data from DB");
         },
         error:function(textStatus, jqXHR){
          alert("Unable to process some of the types, Please check logs for details.");
         }
     });*/
  HttpURLConnection conn = null;
  URL url = new URL("");// just example, in your case pass the URL here
  conn = (HttpURLConnection) url.openConnection();
  conn.setRequestMethod("POST");
  conn.setDoInput(true);
  conn.setDoOutput(true);
  conn.setRequestProperty("Content-Type", "");// just example, in your
             // case pass the content
             // type here
  conn.setRequestProperty("Authorization", "");// just example, in your
              // case pass the
              // authorization key
              // here
  DataOutputStream outputStream = new DataOutputStream(
    conn.getOutputStream());
  outputStream.write(outputString.getBytes());
  outputStream.flush();
  outputStream.close();
  StringBuffer sb = new StringBuffer();
  if (conn != null && conn.getResponseCode() == 200) {
   byte[] buffer = new byte[8192];
   int bytesRead;
   InputStream in = conn.getInputStream();
   while ((bytesRead = in.read(buffer)) != -1) {
    sb.append(new String(buffer, 0, bytesRead, "UTF-8"));
    buffer = new byte[8192];
    bytesRead = 0;
   }
  }
  System.out.println("Output ===>" + sb.toString());
 }
</pre>

In the above example there will not be any preflight Request. because of the Rest API call will be done in server side.