AJAX in Chrome sending OPTIONS instead of GET/POST/PUT/DELETE?
Asked Answered
F

11

111

I am working on an internal web application at work. In IE10 the requests work fine, but in Chrome all the AJAX requests (which there are many) are sent using OPTIONS instead of whatever defined method I give it. Technically my requests are "cross domain." The site is served on localhost:6120 and the service I'm making AJAX requests to is on 57124. This closed jquery bug defines the issue, but not a real fix.

What can I do to use the proper http method in ajax requests?

Edit:

This is in the document load of every page:

jQuery.support.cors = true;

And every AJAX is built similarly:

var url = 'http://localhost:57124/My/Rest/Call';
$.ajax({
    url: url,
    dataType: "json",
    data: json,
    async: true,
    cache: false,
    timeout: 30000,
    headers: { "x-li-format": "json", "X-UserName": userName },
    success: function (data) {
        // my success stuff
    },
    error: function (request, status, error) {
        // my error stuff
    },
    type: "POST"
});
Floorwalker answered 14/2, 2014 at 15:20 Comment(6)
The last comment in that bug report explains it pretty well...Suburbanize
It flipped my mind because everything I'm doing is so vanilla (and my code is similar to that in the jquery bug). That aside, it's no excuse for not including it. BRB, grabbing some sample code.Floorwalker
Note that IE does not consider port numbers when determining if a request is cross-origin.Veii
@KevinB: Our REST service takes advantage of different requests as doing different things based on the http method. Switching everything to GET is not a valid fix. Also, according to Dark Falcon's answer, it won't help anyway because I have X-UserName and other custom headers in the requests.Floorwalker
that doesn't change the fact that if you want to make a cross-origin request, you must follow all of the rules that are applicable to cross-origin requests for it to work properly. cross-origin requests typically involve an OPTIONS request. Handle it properly and the problem will go away. The only other way to solve this (without changing the api) is to have a script on the same server as the primary page that interacts with the api using server-side code.Suburbanize
As it's internal web app you can probably just configure the web server(s) to allow the cross domain request by adding the custom header Access-Control-Allow-Origin: * Old post I know, but google bought me here today and I did not see this possibility listed.Hasan
M
140

Chrome is preflighting the request to look for CORS headers. If the request is acceptable, it will then send the real request. If you're doing this cross-domain, you will simply have to deal with it or else find a way to make the request non-cross-domain. This is why the jQuery bug was closed as won't-fix. This is by design.

Unlike simple requests (discussed above), "preflighted" requests first send an HTTP request by the OPTIONS method to the resource on the other domain, in order to determine whether the actual request is safe to send. Cross-site requests are preflighted like this since they may have implications to user data. In particular, a request is preflighted if:

  • It uses methods other than GET, HEAD or POST. Also, if POST is used to send request data with a Content-Type other than application/x-www-form-urlencoded, multipart/form-data, or text/plain, e.g. if the POST request sends an XML payload to the server using application/xml or text/xml, then the request is preflighted.
  • It sets custom headers in the request (e.g. the request uses a header such as X-PINGOTHER)
Maritzamariupol answered 14/2, 2014 at 15:23 Comment(1)
Custom headers. That's probably what's setting off the preflight OPTIONS calls.Floorwalker
C
18

Based on the fact that the request isn't sent on the default port 80/443 this Ajax call is automatically considered a cross-origin resource (CORS) request, which in other words means that the request automatically issues an OPTIONS request which checks for CORS headers on the server's/servlet's side.

This happens even if you set

crossOrigin: false;

or even if you ommit it.

The reason is simply that localhost != localhost:57124. Try sending it only to localhost without the port - it will fail, because the requested target won't be reachable, however notice that if the domain names are equal the request is sent without the OPTIONS request before POST.

Cubeb answered 7/10, 2014 at 12:58 Comment(0)
H
3

I agree with Kevin B, the bug report says it all. It sounds like you are trying to make cross-domain ajax calls. If you're not familiar with the same origin policy you can start here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Same_origin_policy_for_JavaScript.

If this is not intended to be a cross-domain ajax call, try making your target url relative and see if the problem goes away. If you're really desperate look into the JSONP, but beware, mayhem lurks. There really isn't much more we can do to help you.

Hypocotyl answered 14/2, 2014 at 15:31 Comment(10)
Our system structure is something I can't change. Using a different port is a requirement of our architecture. I get same origin policy but thought that the CORS we implemented was enough. Apparently not.Floorwalker
If your server returns JSON responses, you can look into JSONP method, just use it responsibly.Hypocotyl
JSON has nothing to do with JSONPVeii
I don't really care to argue with you, but JSONP uses script tags to pull in data from another domain and then sends the result to a callback function. It's a lot harder if the result isn't json.Hypocotyl
No, it isn't a lot harder. In fact the response should not be valid JSON in any case. Instead, the server should return something like this: callbackfunc(somedata). As you can see, this is not valid JSON. And, somedata can be a string, or a number, or whatever you want it to be.Veii
Fair enough. But seriously, not arguing.Hypocotyl
@RayNicholus JSONP most definitely has something to do with JSON. While poorly named it is "JSON with padding" where the callback is the padding. While you can use it for other purposes than JSON, the point and intend use of JSONP is to get cross-origin JSON working. en.wikipedia.org/wiki/JSONP "conventionally, it is a JavaScript fragment that invokes a function call on some JSON-formatted data."Nones
JSONP has just as much to do with JSON as it does with HTML, or XML, or <insert data format here>. As you said, JSONP can operate on any data. That was really my point, that and the server does not return JSON, instead, it returns a function invocation.Veii
I'm using Postman and there the request methods are sent correctly (eg. 'PUT', 'DELETE', etc). But when i try to do it from my code it always send them with the request method OPTIONS. I have no idea how Postman is able to do it.Tatianatatianas
i'm encountering too this same scenario @ErwinGO. Probably depends on how postman set his callsLathrop
T
1

If it is possible pass the params through regular GET/POST with a different name and let your server side code handles it.

I had a similar issue with my own proxy to bypass CORS and I got the same error of POST->OPTION in Chrome. It was the Authorization header in my case ("x-li-format" and "X-UserName" here in your case.) I ended up passing it in a dummy format (e.g. AuthorizatinJack in GET) and I changed the code for my proxy to turn that into a header when making the call to the destination. Here it is in PHP:

if (isset($_GET['AuthorizationJack'])) {
    $request_headers[] = "Authorization: Basic ".$_GET['AuthorizationJack'];
}
Tranquilizer answered 12/2, 2016 at 20:54 Comment(0)
B
1

In my case I'm calling an API hosted by AWS (API Gateway). The error happened when I tried to call the API from a domain other than the API own domain. Since I'm the API owner I enabled CORS for the test environment, as described in the Amazon Documentation.

In production this error will not happen, since the request and the api will be in the same domain.

I hope it helps!

Bayer answered 16/6, 2016 at 11:32 Comment(0)
T
0

As answered by @Dark Falcon, I simply dealt with it.

In my case, I am using node.js server, and creating a session if it does not exist. Since the OPTIONS method does not have the session details in it, it ended up creating a new session for every POST method request.

So in my app routine to create-session-if-not-exist, I just added a check to see if method is OPTIONS, and if so, just skip session creating part:

    app.use(function(req, res, next) {
        if (req.method !== "OPTIONS") {
            if (req.session && req.session.id) {
                 // Session exists
                 next();
            }else{
                 // Create session
                 next();
          }
        } else {
           // If request method is OPTIONS, just skip this part and move to the next method.
           next(); 
        }
    }
Tetrachord answered 19/10, 2016 at 13:17 Comment(0)
K
0

"preflighted" requests first send an HTTP request by the OPTIONS method to the resource on the other domain, in order to determine whether the actual request is safe to send. Cross-site requests

https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS

Karolkarola answered 8/5, 2017 at 14:42 Comment(1)
Could you add a bit more information? Your answer looks like a comment. :)Cafeteria
K
0

Consider using axios

axios.get( url,
{ headers: {"Content-Type": "application/json"} } ).then( res => {

  if(res.data.error) {

  } else { 
    doAnything( res.data )
  }

}).catch(function (error) {
   doAnythingError(error)
});

I had this issue using fetch and axios worked perfectly.

Kreutzer answered 12/11, 2017 at 15:38 Comment(1)
Axios also use first OPTIONSOscine
A
0

I've encountered a very similar issue. I spent almost half a day to understand why everything works correctly in Firefox and fails in Chrome. In my case it was because of duplicated (or maybe mistyped) fields in my request header.

Archfiend answered 26/5, 2018 at 17:50 Comment(0)
T
0

Use fetch instead of XHR,then the request will not be prelighted even it's cross-domained.

Tanika answered 10/12, 2019 at 10:7 Comment(0)
A
-1
 $.ajax({
            url: '###',
            contentType: 'text/plain; charset=utf-8',
            async: false,
            xhrFields: {
                withCredentials: true,
                crossDomain: true,
                Authorization: "Bearer ...."
            },

            method: 'POST',

            data: JSON.stringify( request ),
            success: function (data) {
                console.log(data);
            }
        });

the contentType: 'text/plain; charset=utf-8', or just contentType: 'text/plain', works for me! regards!!

Agace answered 21/8, 2019 at 8:56 Comment(4)
What does this have to do with the question at all?Floorwalker
HI, I think this solve the problem in the title, with this content type you pass the OPTIONS method. RegardsAgace
ContentType has nothing to do with the method.Floorwalker
I know what you are saying, but give it a try. depending the browser your content-type can influence your request and change your Method!Agace

© 2022 - 2024 — McMap. All rights reserved.