One of the major limitations of Ajax communication via XHR is the cross-origin security policy. By default, XHR objects can access resources only on the domain from which the containing web page originates. This security feature prevents some malicious behavior. However, the need for legitimate cross-origin access was great enough for solutions to begin appearing in browsers.
Cross-Origin Resource Sharing (CORS) defines how the browser and server must communicate when accessing sources across origins. The basic idea behind CORS is to use custom HTTP headers to allow both the browser and the server to know enough about each other to determine if the request or response should succeed or fail.
For a simple request, one that uses either GET or POST with no custom headers and whose body is text/plain, the request is sent with an extra header called Origin
. The Origin
header contains the origin (protocol, domain name, and port) of the requesting page so that the server can easily determine whether or not it should serve a response. An example Origin
header might look like this:
Origin: http://www.nczonline.net
If the server decides that the request should be allowed, it sends an Access-Control-Allow-Origin
header echoing back the same origin that was sent or “*” if it’s a public resource. For example:
Access-Control-Allow-Origin: http://www.nczonline.net
If this header is missing, or the origins don’t match, then the browser disallows the request. If all is well, then the browser processes the request. Note that neither the requests nor the responses include cookie information.
Modern browsers support CORS natively through the XMLHttpRequest
object. When attempting to open a resource on a different origin, this behavior automatically gets triggered without any extra code. To make a request to a resource on another domain, the standard XHR object is used with an absolute URL specified in open()
, such as this:
let xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
if (xhr.readyState == 4) {
if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304) {
alert(xhr.responseText);
} else {
alert("Request was unsuccessful: " + xhr.status);
}
}
};
xhr.open("get", "http://www.somewhere-else.com/page/", true);
xhr.send(null);
The cross-domain XHR object allows access to the status
and statusText
properties and allows synchronous requests. There are some additional limitations on a cross-domain XHR object that are necessary for security purposes. They are as follows:
setRequestHeader()
.getAllResponseHeaders()
method always returns an empty string.Because the same interface is used for both same- and cross-domain requests, it’s best to always use a relative URL when accessing a local resource, and an absolute URL when accessing a remote resource. This disambiguates the use case and can prevent problems such as limiting access to header and/or cookie information for local resources.