Why am I getting an OPTIONS request instead of a GET request?
Asked Answered
S

10

334
<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?

Saker answered 10/8, 2009 at 18:55 Comment(1)
Could be cos of cross domain. E.g if you are on your file File://PATH_TO_WEBSITE instead of using localhost/WEBSITE_LINKNash
C
304

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)
Cindy answered 23/10, 2012 at 12:41 Comment(9)
this fixed our problem, changing from "application/json" to "text/plain" stopped the horrible options requestPneumococcus
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 ?Vaso
@Vaso 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.Barman
@Barman 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)Congenital
"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 RequestsTroutman
how to send custom header X-Authentication containing token without OPTIONS being sent then?Aliped
You guys can just check for OPTIONS in your code (above all the other rules) and just return a 200 response for it.Franks
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.Freer
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.Modiolus
B
12

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"
    });
}
Boabdil answered 5/4, 2017 at 21:58 Comment(0)
D
3

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,
    });
Duckling answered 22/9, 2017 at 16:5 Comment(0)
I
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.

Inevitable answered 10/8, 2009 at 21:14 Comment(2)
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.Saker
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.Inevitable
B
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).

Bluey answered 10/8, 2009 at 19:49 Comment(1)
right, but I can load it in a <script src=""> or <img src=""> and the browser will happily hit it. I just want to know when it is fully loaded so i can query for the result of the import.Saker
H
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.

Hippie answered 21/2, 2018 at 19:1 Comment(2)
Exactly where do you add this in the php file?Triserial
I believe you can put it anywhere within your php code as long as it executes for each incoming request.Hippie
M
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.

Malcom answered 12/11, 2018 at 15:52 Comment(0)
I
1

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();
});
Indecorous answered 17/7, 2019 at 14:43 Comment(0)
D
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.

Deviltry answered 10/8, 2009 at 19:18 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.