XMLHttpRequest changes POST to OPTION

Yes, this is a "problem with same-origin policy". You are making your request either to a different server or to a different port, meaning that it is a cross-site HTTP request. Here is what the documentation has to say about such requests:

Additionally, for HTTP request methods that can cause side-effects on server's data (in particular, for HTTP methods other than GET, or for POST usage with certain MIME types), the specification mandates that browsers "preflight" the request, soliciting supported methods from the server with an HTTP OPTIONS request method, and then, upon "approval" from the server, sending the actual request with the actual HTTP request method.

There is a more detailed description in the CORS standard ("Cross-Origin Request with Preflight" section). Your server needs to allow the OPTIONS request and send a response with Access-Control-Allow-Origin, Access-Control-Allow-Headers and Access-Control-Allow-Methods headers allowing the request. Then the browser will make the actual POST request.


I was having this exact problem from a JavaScript code that sent an ajax content.

In order to allow the Cross-Origin Request with Preflight I had to do this in the .ASPX that was receiving the petition:

//Check the petition Method
if (Request.HttpMethod == "OPTIONS")
{
    //In case of an OPTIONS, we allow the access to the origin of the petition
    string vlsOrigin = Request.Headers["ORIGIN"];
    Response.AddHeader("Access-Control-Allow-Origin", vlsOrigin);
    Response.AddHeader("Access-Control-Allow-Methods", "POST");
    Response.AddHeader("Access-Control-Allow-Headers", "accept, content-type");
    Response.AddHeader("Access-Control-Max-Age", "1728000");
}

You have to be careful and check what headers are being asked by your petition. I checked those using Fiddler.

Hope this serves someone in the future.


Answer:

Your browser is initiating a PreFlight OPTIONS request.

Why: Because your request is not a simple request.

Why it is not a simple request: Because of "Content-Type" = "application/json".

Solution: Try to use either of below content types :

  • application/x-www-form-urlencoded
  • multipart/form-data
  • text/plain

As others have pointed out, this is a CORS thing.

This is how to handle it in NGINX (based on this source):

location / {
    if ($request_method = OPTIONS ) {
        add_header Access-Control-Allow-Origin "http://example.com";
        add_header Access-Control-Allow-Methods "GET, OPTIONS";
        add_header Access-Control-Allow-Headers "Authorization";
        add_header Access-Control-Allow-Credentials "true";
        add_header Content-Length 0;
        add_header Content-Type text/plain;
        return 200;
    }
}

If you want to allow CORS requests from any origin, replace,

add_header Access-Control-Allow-Origin "http://example.com";

with

add_header Access-Control-Allow-Origin "*";

If you don't use authorization, you won't need this bit:

add_header Access-Control-Allow-Headers "Authorization";
add_header Access-Control-Allow-Credentials "true";

For the API I'm developing I needed to whitelist 3 request methods: GET, POST and OPTIONS, and an X-App-Id header, so this us what I ended up doing:

if ($request_method = OPTIONS ) {
    add_header Access-Control-Allow-Origin "*";
    add_header Access-Control-Allow-Methods "GET, POST, OPTIONS";
    add_header Access-Control-Allow-Headers "X-App-Id";
    add_header Content-Length 0;
    add_header Content-Type text/plain;
    return 200;
}