AJAX: Status of “0” for an XMLHttpRequest

If you experience getting a status of "0" returned during an XMLHttpRequest, then the problem could be the result of several things. However, a status of "0" for an XMLHttpRequest (XHR) in AJAX quite often indicates a network error or a CORS (Cross-Origin Resource Sharing) issue. You might especially see this problem if you're developing on a local machine, and trying to access a remote resource of some sort (which could be a script, or image, or font, etc.). Cue the Access-Control-Allow-Origin header!

Just Quickly ...

If you're not familiar with CORS, then it's basically a web security mechanism that allows a web resource  at one domain, or point of origin, to access a resource from a different domain. This is what constitutes a cross-domain request.

How to Fix it

First of all, before you excitedly get to work on tweaking your server, you really need to know that the status of 0 error you're getting is actually because of CORS. If you already got a message such as "XMLHttpRequest cannot load. Origin is not allowed by Access-Control-Allow-Origin" then you're all set, but if not then you may want to investigate further, before assuming that the problem is CORS-related.

Useful information on obtaining the status and status text from an XMLHttpRequest can be found using the MDN web docs. For example:

const xhr = new XMLHttpRequest();
console.log('0 Unsent', xhr.statusText);

xhr.open('GET', '/server', true);
console.log('1 Opened', xhr.statusText);

xhr.onprogress = () => { console.log('3 Loading', xhr.statusText); };

xhr.onload = () => { console.log('4 Done', xhr.statusText); };

xhr.send(null);

And the output would provide:

0 Unsent
1 Opened
3 Loading OK
4 Done OK

Having once identified the fact that it is a cross-origin problem then how does one go about fixing it? It's really not too difficult. Depending on your circumstance or needs, then you might resolve the problem in one of a couple of ways. One way is to use JSONP (JSON with Padding), as discussed at the link provided. Another way, as noted below, is to ensure that your server response headers allow for such cross-domain requests.

Access-Control-Allow-Origin

So, in the instance of an Apache web-server, one would add the "Access-Control-Allow-Origin" header in the Apache configuration. To do this you can use the Header directive in the Apache configuration file (usually located at /etc/httpd/conf/httpd.conf or /etc/apache2/httpd.conf, depending on your flavor of Linux) or in a .htaccess file in the relevant location.

Also, to set headers in Apache you'll need to have the headers module enabled, if it isn't already. There's a good chance it's already enabled in your configuration, but if not then you should ensure the following line is enabled in the Apache configuration file, httpd.conf:

LoadModule headers_module modules/mod_headers.so

Then, for example, to permit all origins (i.e. to allow requests from everywhere), you could use the following configuration:

<Directory /path/to/your/directory>
  Header set Access-Control-Allow-Origin "*"
</Directory>

However, allowing all origins (i.e. "*") can provide a much larger security risk than is necessary, so only use the wildcard if your site or application really, really needs it. Much better, if possible, is to allow only the domain(s) which requires the access, such as this:

<Directory /path/to/your/directory>
  Header set Access-Control-Allow-Origin https://www.mysite1.com
  Header set Access-Control-Allow-Origin https://www.mysite2.com
</Directory>

You must also remember to include the protocol when adding the allowed domain(s). That is, you must ensure to include the "https://" (or whatever the protocol you wish to allow). Also, you cannot supply more than one origin for each Access-Control-Allow-Origin statement. That is, you cannot list several comma-separated domains, for example, using the same statement.

After making your modifications, you should restart Apache for the changes to take effect. You should now be able to make your cross-origin requests without any problems.