There’s no doubt that Ajax is one of the most exciting, useful, and necessary web technologies available to front-end developers. Unfortunately, it’s also one of the most restrictive — especially when it comes to gathering content from other domains. Web developers are nothing if not persistent, so we’ve come up with a variety of ways to get around cross-origin restrictions, including JSONP, server-side proxies made with PHP, ProxyPass proxying, Flash transports, creative iFrame uses, and more. What many developers don’t know is that there’s a W3C specification called Cross-Origin Resource Sharing, or CORS, which provides a standard for cross-origin Ajax requests with minimal hassle.
Since the Ajax API is different across browsers, and most developers use a JavaScript toolkit, examples within this post will use the MooTools JavaScript framework. CORS will work with any JavaScript framework, since the core philosophy and code is configured on the server, not the client side. Due to its popularity, Apache will be used in server-side configuration examples.
Basic Ajax RequestsEach of the JavaScript frameworks abstracts XM [HttpRequest] objects (or in the case of Internet Explorer, ActiveXObject or Microsoft.XMLHttp) to make Ajax requests. These requests feature a URL and may contain extra headers, data, different request types (GET, POST, PUT, or DELETE), and much more. A basic Ajax request would look something like this:
// Create a new Ajax request
var request = new Request.JSON({
// The URL to get content from
url: "/countries.json",
// The success callback
onSuccess: function(countries) {
// Log out the content
console.log("The countries are: ", countries);
}
}).send(); // Send the request
The URL within the request above is local; countries.json is located within the same origin. What if we try to get tweets from Twitter, though?
// Create a new Ajax request
var request = new Request.JSON({
// The URL to get content from
url: "http://twitter.com/statuses/user_timeline/davidwalshblog.json",
// The success callback
onSuccess: function(tweets) {
// Log out the content
console.log("The tweets are: ", content);
}
}).send(); // Send the request
The request to Twitter will fail because the request destination, twitter.com, is not the same as the origin. Each browser provides its own error message; Chrome will warn you with: XM [HttpRequest] cannot load [twitter.com] Origin [davidwalsh.name] is not allowed by Access-Control-Allow-Origin.
In the case of Twitter, we could use a JSONP request instead, but the problem with JSONP is that the destination server must support it. Even if the destination supports JSONP, you cannot POST to the URL or send specified request headers. How do we fix this conundrum? CORS, of course.
CORS allows for cross-origin requests with little fuss. Since the destination server is the entity in control and “at risk,” it must be configured with the proper headers and security settings. A few of the key headers include:
Access-Control-Allow-Origin
A specific URI or * which identifies what domain(s) may make cross-origin requests to this (destination) server. (* is an undesirable configuration value, since it allows any and all origins to make requests to your server.)
Access-Control-Allow-Methods
A comma-separated list of allowed request methods.
Access-Control-Allow-Headers
A comma-separated list of allowed request headers.
Assuming that a web site is hosted on an Apache server, the virtual host could be configured as follows:
<VirtualHost *:80>
DocumentRoot "/path/to/website/root"
ServerName domain.tld
Header set Access-Control-Allow-Origin [example.com] Header set Access-Control-Allow-Methods POST,GET
Header set Access-Control-Allow-Headers X-Authorization,X-Requested-With
</VirtualHost>
The configuration above only allows remote requests from http://example.com, the request type may only be POST or GET, and allowed headers are X-Authorization and X-Requested-With.
If you want to allow anyone to make Ajax requests to your domain and with any request type, you could opt for this configuration:
<VirtualHost *:80>
DocuTruncated by Planet PHP, read more at the original (another 1795 bytes)