Any good REST API requires the use of four HTTP methods (or REST Verbs), GET, POST, PUT and DELETE. They also allow you to say what format you would like your response to be returned as (XML and JSON seem to be the most common types)
By default it’s not possible to request a URL from a domain other than that which the requesting page came from. This presents a bit of a problem if you’re trying to get data from a web service API.
The reason behind this is not immediately obvious. It’s not that the browser will refuse to access an external domain, it’s actually that the domain in question won’t explicitly tell the browser that it will accept the request.
What actually happens is this:
- Page Load: The browser loads the page. At some point an XMLHttpRequest object is created, properties are set, and the call is made
- Preflight: The browser issues an OPTIONS http request to the URL passed in to the XMLHttpRequest object. In the header of this request, it sets the Origin to that of the domain where the page was loaded from.
- Authorisation: The server responds with (most likely) either a 403 (Not Allowed) or a 200 (OK) code, but with otherwise standard headers
- Failure: The XMLHttpRequest object cancels the load, moves to readyState 4, with a status of 0
So the browser did attempt to access the URL, but the server didn’t say it would accept a Cross-Site request!
What we really need is get the server to tell the browser explicitly that it will accept requests from an origin other than itself. To do this, we need to do just two things:
- Enable the Apache Headers module
- a2enmod headers
- service apache restart
- In our Apache config for the site, under the <Directory> section, add
- Headers set Access-Control-Allow-Origin “*”
- Header add Access-Control-Allow-Headers “origin, content-type”
- Header always set Access-Control-Allow-Methods “POST, GET, PUT, DELETE, OPTIONS”
When we try again now, we should see the response to the OPTIONS request contains the headers we asked it to add.
You’ll notice we’re explicitly setting the following things:
- We will allow requests from ANY (*) origin
- We will allow 5 different HTTP methods (POST, GET, PUT, DELETE and of course, OPTIONS)
- We will allow Cross-Site requests to include Origin, Content-Type and headers.
Now our XMLHttpRequest object is happy that the server will accept a request from us, so there will then be a second request, which is the one we actually wanted to get our data.
The same directives can be set in the .htaccess file if you don;t have direct access to your servers Apache conf files.