13

I attempt to send a GET request in a jQuery AJAX request.

$.ajax({
    type: 'GET',
    url: /* <the link as string> */,
    dataType: 'text/html',
    success: function() { alert("Success"); },
    error: function() { alert("Error"); },
});

However, whatever I've tried, I got XMLHttpRequest cannot load <page>. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:7776' is therefore not allowed access.

I tried everything, from adding header : {} definitions to the AJAX request to setting dataType to JSONP, or even text/plain, using simple AJAX instead of jQuery, even downloading a plugin that enables CORS - but nothing could help.

And the same happens if I attempt to reach any other sites.

Any ideas for a proper and simple solution? Is there any at all?

Zoltán Schmidt
  • 1,286
  • 2
  • 28
  • 48
  • You can't make ajax request to another domain because CORS (Cross-origin resource sharing), unless the other domain (in this case stackoverflow) allow it. – Pipe Feb 10 '16 at 00:34
  • 2
    You can't get around same-origin policy on the browser alone because it would completely defeat its purpose. – JJJ Feb 10 '16 at 00:34
  • @Juhana and that answer was **also** from Stack Overflow! – Zoltán Schmidt Feb 10 '16 at 00:36
  • 1
    No idea what you're trying to say but ok. – JJJ Feb 10 '16 at 00:37
  • @Juhana Your comment implied that a browser plugin is a ridiculous and nonsensical method for solving this issue. I highlighted that the idea of doing so is also coming from this site, which I think shows that even here, terrible answers can be given without downvoting. Which is sad, but I'm not judging the site quality, of course. – Zoltán Schmidt Feb 10 '16 at 00:40

3 Answers3

7

This is by design. You can't make an arbitrary HTTP request to another server using XMLHttpRequest unless that server allows it by putting out an Access-Control-Allow-Origin header for the requesting host.

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

You could retrieve it in a script tag (there isn't the same restriction on scripts and images and stylesheets), but unless the content returned is a script, it won't do you much good.

Here's a tutorial on CORS:

http://www.bennadel.com/blog/2327-cross-origin-resource-sharing-cors-ajax-requests-between-jquery-and-node-js.htm

This is all done to protect the end user. Assuming that an image is actually an image, a stylesheet is just a stylesheet and a script is just a script, requesting those resources from another server can't really do any harm.

But in general, cross-origin requests can do really bad things. Say that you, Zoltan, are using coolsharks.com. Say also that you are logged into mybank.com and there is a cookie for mybank.com in your browser. Now, suppose that coolsharks.com sends an AJAX request to mybank.com, asking to transfer all your money into another account. Because you have a mybank.com cookie stored, they successfully complete the request. And all of this happens without your knowledge, because no page reload occurred. This is the danger of allowing general cross-site AJAX requests.

If you want to perform cross-site requests, you have two options:

  1. Get the server you are making the request to to either
    a. Admit you by putting out a Access-Control-Allow-Origin header that includes you (or *)
    b. Provide you with a JSONP API.

or

  1. Write your own browser that doesn't follow the standards and has no restrictions.

In (1), you must have the cooperation of the server you are making requests to, and in (2), you must have control over the end user's browser. If you can't fulfill (1) or (2), you're pretty much out of luck.

However, there is a third option (pointed out by charlietfl). You can make the request from a server that you do control and then pass the result back to your page. E.g.

<script>
$.ajax({
    type: 'GET',
    url: '/proxyAjax.php?url=http%3A%2F%2Fstackoverflow.com%2F10m',
    dataType: 'text/html',
    success: function() { alert("Success"); },
    error: function() { alert("Error"); }
});
</script>

And then on your server, at its most simple:

<?php
// proxyAjax.php
// ... validation of params
// and checking of url against whitelist would happen here ...
// assume that $url now contains "http://stackoverflow.com/10m"
echo file_get_contents($url);

Of course, this method may run into other issues:

  • Does the site you are a proxy for require the correct referrer or a certain IP address?
  • Do cookies need to be passed through to the target server?
  • Does your whitelist sufficiently protect you from making arbitrary requests?
  • Which headers (e.g. modify time, etc) will you be passing back to the browser as your server received them and which ones will you omit or change?
  • Will your server be implicated as having made a request that was unlawful (since you are acting as a proxy)?

I'm sure there are others. But if none of those issues prevent it, this third method could work quite well.

Chris Middleton
  • 5,654
  • 5
  • 31
  • 68
  • 1
    missing #3 which is use a proxy on domain you do control to make request and return wanted resource – charlietfl Feb 10 '16 at 00:49
  • and then there are 3rd party proxies like Yahoo YQL – charlietfl Feb 10 '16 at 00:55
  • Thank you for the explanation! Does it mean that (if I don't want to use a proxy, then) my only method in any cases if I get a JSONP API? – Zoltán Schmidt Feb 10 '16 at 01:17
  • 1
    @Zoltan. Yes, without using a proxy, getting a JSONP API would be your best shot when trying to request pages from a popular site. (They're not likely to put your origin or \* in their headers.) Keep in mind however that a JSONP API is not generally created for just requesting arbitrary navigable pages of a site (such as the "/10m" link in your question.). It's typically used where you would be receiving JSON, not HTML. – Chris Middleton Feb 10 '16 at 01:44
  • 1
    Therefore, there are sites that I won't ever be able to `GET` under no circumstances, am I right? Without proxy of course. – Zoltán Schmidt Feb 10 '16 at 02:16
3

you can ask the developers of that domain if they would set the appropriate header for you, this restriction is only for javascript, basically you can request the ressource from your server with php or whatever and the javascript requests the data from your domain then

john Smith
  • 17,409
  • 11
  • 76
  • 117
0

Old question, but I'm not seeing this solution, which worked for me, anywhere. So hoping this can be helpful for someone.

First, remember that it makes no sense to try modifying the headers of the request to get around a cross-origin resource request. If that were all it took, it would be easy for malicious users to then circumvent this security measure.

Cross-origin requests in this context are only possible if the partner site's server allows it through their response headers.

I got this to work in Django without any CORS middleware by setting the following headers on the response:

    response["Access-Control-Allow-Origin"] = "requesting_site.com"
    response["Access-Control-Allow-Methods"] = "GET"
    response["Access-Control-Allow-Headers"] = "requesting_site.com"

Most answers on here seem to mention the first one, but not the second two. I've just confirmed they are all required. You'll want to modify as needed for your framework or request method (GET, POST, OPTION).

p.s. You can try "*" instead of "requesting_site.com" for initial development just to get it working, but it would be a security hole to allow every site access. Once working, you can restrict it for your requesting site only to make sure you don't have any formatting typos.

Joel Wigton
  • 642
  • 6
  • 15