Ajax Requests to Other Domains with Cross-Origin Resource Sharing
Ajax requests can only point to URLs on the exact same domain. See how to solve this issue.
Join the DZone community and get the full member experience.
Join For FreeJavaScript can execute Ajax requests through the XMLHttpRequest object; these requests are no different from HTTP requests performed by the browser when an URL is type in or a form is submitted. However, Ajax requests can only point to URLs on the exact same domain (complete of port and http[s]:// protocol) of the page where the JavaScript code is executed - basically where the <script> tags reside.
This Same Origin Policy is a basic security mechanism implemented by all browsers starting from Netscape: it stops a malicious website executing Ajax requests to gmail.com and stealing your data.
However, the policy is also a limitation: it forces a rich JavaScript-based client to only request data to your own webserver, instead of being able to access 3rd party web services.
Solutions
The first solutions to the limitations of the Same Origin Policy were hacks like using your own domain as a proxy: on the server-side it's easy to perform HTTP requests to any domain, with no limitations. This solution however duplicates the traffic you have to substain, instead of targeting directly the 3rd party.
JSONP is an old, reliable technique that use the <script> tag to include a script from the 3rd party domain that will executed in the same scope of the current page. This script will usually just pass the data to a callback specified by yuor own code, and since it is loaded via a <script> tag it only works for GET requests.
Cross-Origin Resource Sharing is the most modern technique, and it is implemented in major browsers (with the notable exception of Opera). It allows requests to other domains for a certain subset of URLs - the ones that return an HTTP header explicitly authorizing your domain to work with them.
How Cross-Origin Resource Sharing works
Remote domains that wish to allow cross-origin requests to them should add the HTTP header Access-Control-Allow-Origin to their output, on a per-page basis or on all their URLs.
The content of the header may show that requests from everywhere are allowed:
Access-Control-Allow-Origin: *
Or it may list the only websites allowed, separated by spaces. The domain must be complete with http://, and with :port where it is not the default (80). A domain in the SOP sense is defined as protocol, domain and port.
Access-Control-Allow-Origin: http://google.com http://example.com
Given the intervention on HTTP headers of the target domain, there are two use cases for CORS:
- websites publishing open data, which add the header by themselves. Several .gov websites are doing so.
- Websites under your control, where you can add the header to all the pages you need.
Since CORS uses the XMLHttpRequest objects, it allows you to use the same API for all requests (e.g. jQuery), and to handle errors like you're doing for local resources.
Sample code
These code samples were tested with current version of Chrome. I configured a remotedomain virtual host on my Apache instance, pointing to another folder on localhost.
My remote data was published at http://remotedomain/data.php:
<?php
echo json_encode(array(
'field' => 'value'
));
This was the page from localhost requesting it:
<html>
<head>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
<script type="text/javascript">
$(function() {
$('#content').load('http://remotedomain/data.php');
});
</script>
</head>
<body>
<div id="content"></div>
</body>
</html>
This example won't work as-is:
However, if we add the header for CORS to the output from data.php:
<?php
header("Access-Control-Allow-Origin: *");
echo json_encode(array(
'field' => 'value'
));
We get this displayed into the div of the request page:
{"field":"value"}
Note that the client code isn't changed, something which is necessary for other approaches like JSONP (although well-supported internally by jQuery and other frameworks).
Resources
The Mozilla Developer Network page on HTTP access control goes in depth into explaining other Access-Control headers, which enable other use cases like requests with credentials. Seriously, you should send to developer.mozilla.org any fool who pitch you w3schools.com.
Enable Cors has instructions for enabling the headers on different servers such as Apache and IIS, but also to add it at the page level with PHP, ASP.NET or even Google App Engine. It lists a series of public datasets already serving content in this manner.
CanIUse lists all the browsers supporting CORS, along with versions and their timeline. Fortunately, the table is mostly green.
Opinions expressed by DZone contributors are their own.
Comments