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:
- 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
- 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.
Best Answer
You won't be able to make an ajax call to
http://www.ecb.europa.eu/stats/eurofxref/eurofxref-daily.xml
from a file deployed athttp://run.jsbin.com
due to the same-origin policy.As the source (aka origin) page and the target URL are at different domains (
run.jsbin.com
andwww.ecb.europa.eu
), your code is actually attempting to make a Cross-domain (CORS) request, not an ordinaryGET
.In a few words, the same-origin policy says that browsers should only allow ajax calls to services at the same domain of the HTML page.
Example:
A page at
http://www.example.com/myPage.html
can only directly request services that are athttp://www.example.com
, likehttp://www.example.com/api/myService
. If the service is hosted at another domain (sayhttp://www.ok.com/api/myService
), the browser won't make the call directly (as you'd expect). Instead, it will try to make a CORS request.To put it shortly, to perform a (CORS) request* across different domains, your browser:
Origin
header in the original request (with the page's domain as value) and perform it as usual; and thenAccess-Control-Allow-Origin
is one of them) allowing the CORS request, the browse will complete the call (almost** exactly the way it would if the HTML page was at the same domain).* The above depicts the steps in a simple request, such as a regular
GET
with no fancy headers. If the request is not simple (like aPOST
withapplication/json
as content type), the browser will hold it a moment, and, before fulfilling it, will first send anOPTIONS
request to the target URL. Like above, it only will continue if the response to thisOPTIONS
request contains the CORS headers. ThisOPTIONS
call is known as preflight request.** I'm saying almost because there are other differences between regular calls and CORS calls. An important one is that some headers, even if present in the response, will not be picked up by the browser if they aren't included in the
Access-Control-Expose-Headers
header.How to fix it?
Was it just a typo? Sometimes the JavaScript code has just a typo in the target domain. Have you checked? If the page is at
www.example.com
it will only make regular calls towww.example.com
! Other URLs, such asapi.example.com
or evenexample.com
orwww.example.com:8080
are considered different domains by the browser! Yes, if the port is different, then it is a different domain!Add the headers. The simplest way to enable CORS is by adding the necessary headers (as
Access-Control-Allow-Origin
) to the server's responses. (Each server/language has a way to do that - check some solutions here.)Last resort: If you don't have server-side access to the service, you can also mirror it (through tools such as reverse proxies), and include all the necessary headers there.