304
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.js" type="text/javascript"></script>
<script>
$.get("http://example.com/", function(data) {
     alert(data);
});
</script>

it does an OPTIONS request to that URL, and then the callback is never called with anything.

When it isn't cross domain, it works fine.

Shouldn't jQuery just make the call with a <script> node and then do the callback when its loaded? I understand that I won't be able to get the result (since it is cross domain), but that's OK; I just want the call to go through. Is this a bug, or am I doing something wrong?

Paul Tarjan
  • 44,540
  • 54
  • 163
  • 207
  • 2
    Could be cos of cross domain. E.g if you are on your file File://PATH_TO_WEBSITE instead of using localhost/WEBSITE_LINK – James111 Dec 22 '15 at 03:47

10 Answers10

277

According to MDN,

Preflighted requests

Unlike simple requests (discussed above), "preflighted" requests first send an HTTP OPTIONS request header 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 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)
Rafael Eyng
  • 3,892
  • 1
  • 30
  • 34
arturgrigor
  • 8,811
  • 4
  • 28
  • 31
  • 46
    this fixed our problem, changing from "application/json" to "text/plain" stopped the horrible options request – Keeno Jul 12 '13 at 09:44
  • 10
    what i don't understand is why browser is requesting with OPTIONS method just to check the actual request is safe to send. but in what sense ? i mean server can also put restrictions with certain response headers so why this is needed ? – hardik Jul 03 '14 at 13:36
  • 13
    @hardik Remember that by adding CORS, you're potentially accepting requests from anyone, in which they could manipulate data on your server through requests (POST, PUT, DELETE etc). In these situations, like when using custom headers, the browser is just checking with the server first that the server is willing to accept the request before sending it as sending unsolicited requests to the server could be really dangerous for your data, and also, what's the point in the browser sending potentially large payloads if the server isn't wanting to accept them, hence the pre-flight OPTIONS check. – davidnknight Aug 19 '14 at 09:25
  • 6
    @davidnknight if sending your data to the server can be dangerous, meaning the server might be compromised, then of course the malicious server would respond to your OPTIONS request with "Sure, send it all over!". How is that security? (honest question) – Matt Jun 30 '16 at 02:58
  • 3
    "preflight requests are not a security thing. Rather, they're a not-changing-the-rules thing." - See the answer to [What is the Motivation Behind Introducing Preflight Requests](https://stackoverflow.com/questions/15381105/cors-what-is-the-motivation-behind-introducing-preflight-requests) – FMJaguar Jan 20 '17 at 18:53
  • how to send custom header X-Authentication containing token without OPTIONS being sent then? – Michail Michailidis Feb 05 '17 at 13:34
  • You guys can just check for OPTIONS in your code (above all the other rules) and just return a 200 response for it. – Vahid Amiri Aug 06 '17 at 07:56
  • 1
    The whole CORS spec is strange: what's the point of disallowing custom headers if developers of major APIs as a result move them to the URL as query parameter? This spec is not well adjusted to reality or vice versa. – B M Sep 23 '17 at 18:50
  • 1
    Preflight is used to verify that server is expecting "non-standard" cross-origin requests. XHR (ajax) queries can send requests that browsers otherwise cannot send (e.g. `PUT`, `DELETE`). CORS is designed to prevent indirect attack towards your server using browsers of visitors on some 3rd party site. – Mikko Rantalainen Sep 28 '17 at 08:01
92

The OPTIONS is from http://www.w3.org/TR/cors/ See http://metajack.im/2010/01/19/crossdomain-ajax-for-xmpp-http-binding-made-easy/ for a bit more info

Paul Tarjan
  • 44,540
  • 54
  • 163
  • 207
9

If you're trying to POST

Make sure to JSON.stringify your form data and send as text/plain.

<form id="my-form" onSubmit="return postMyFormData();">
    <input type="text" name="name" placeholder="Your Name" required>
    <input type="email" name="email" placeholder="Your Email" required>
    <input type="submit" value="Submit My Form">
</form>

function postMyFormData() {

    var formData = $('#my-form').serializeArray();
    formData = formData.reduce(function(obj, item) {
        obj[item.name] = item.value;
        return obj;
    }, {});
    formData = JSON.stringify(formData);

    $.ajax({
        type: "POST",
        url: "https://website.com/path",
        data: formData,
        success: function() { ... },
        dataType: "text",
        contentType : "text/plain"
    });
}
Derek Soike
  • 8,670
  • 1
  • 64
  • 67
2

I don't believe jQuery will just naturally do a JSONP request when given a URL like that. It will, however, do a JSONP request when you tell it what argument to use for a callback:

$.get("http://metaward.com/import/http://metaward.com/u/ptarjan?jsoncallback=?", function(data) {
     alert(data);
});

It's entirely up to the receiving script to make use of that argument (which doesn't have to be called "jsoncallback"), so in this case the function will never be called. But, since you stated you just want the script at metaward.com to execute, that would make it.

VoteyDisciple
  • 35,315
  • 5
  • 85
  • 89
  • would MY callback still be notified that the script element has fully loaded? I just want to make sure the update happened before I query the API for it. – Paul Tarjan Aug 10 '09 at 21:38
  • You will if the receiving script supports JSONP, and is willing to call the function you identify. If the script does nothing but generate a block of JSON data with no other behavior, you won't be able to tell when it's done loading. If it's essential to tell when it's done loading, you might consider implementing a script on your own server that acts as a proxy. – VoteyDisciple Aug 11 '09 at 11:25
1

In fact, cross-domain AJAX (XMLHttp) requests are not allowed because of security reasons (think about fetching a "restricted" webpage from the client-side and sending it back to the server – this would be a security issue).

The only workaround are callbacks. This is: creating a new script object and pointing the src to the end-side JavaScript, which is a callback with JSON values (myFunction({data}), myFunction is a function which does something with the data (for example, storing it in a variable).

Adrián Navarro
  • 503
  • 3
  • 13
  • 1
    right, but I can load it in a – Paul Tarjan Aug 10 '09 at 21:39
1

Just change the "application/json" to "text/plain" and do not forget the JSON.stringify(request):

var request = {Company: sapws.dbName, UserName: username, Password: userpass};
    console.log(request);
    $.ajax({
        type: "POST",
        url: this.wsUrl + "/Login",
        contentType: "text/plain",
        data: JSON.stringify(request),

        crossDomain: true,
    });
David Lopes
  • 402
  • 3
  • 9
1

I had the same problem. My fix was to add headers to my PHP script which are present only when in dev environment.

This allows cross-domain requests:

header("Access-Control-Allow-Origin: *");

This tells the preflight request that it is OK for the client to send any headers it wants:

header("Access-Control-Allow-Headers: *");

This way there is no need to modify the request.

If you have sensitive data in your dev database that might potentially be leaked, then you might think twice about this.

fivebit
  • 29
  • 3
1

In my case, the issue was unrelated to CORS since I was issuing a jQuery POST to the same web server. The data was JSON but I had omitted the dataType: 'json' parameter.

I did not have (nor did I add) a contentType parameter as shown in David Lopes' answer above.

GarDavis
  • 1,189
  • 2
  • 13
  • 22
0

It's looking like Firefox and Opera (tested on mac as well) don't like the cross domainness of this (but Safari is fine with it).

You might have to call a local server side code to curl the remote page.

helloandre
  • 9,999
  • 6
  • 42
  • 62
0

I was able to fix it with the help of following headers

Access-Control-Allow-Origin
Access-Control-Allow-Headers
Access-Control-Allow-Credentials
Access-Control-Allow-Methods

If you are on Nodejs, here is the code you can copy/paste.

app.use((req, res, next) => {
  res.header('Access-Control-Allow-Origin','*');
  res.header('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept');
  res.header('Access-Control-Allow-Credentials', true);
  res.header('Access-Control-Allow-Methods', 'GET, POST, PUT, PATCH');
  next();
});
obai
  • 349
  • 5
  • 11