Tuesday, November 20th, 2007
He discusses the high level, and then delves into the requirements and process for getting cross domain code working:
The “setup” required at the client’s end is that he should have at least one static cacheable resource embedded in the page where he’s consuming the API, which is loaded from the same domain as his page. This could be in the form of a static CSS file, or an image. If the page doesn’t have either, it will be required to insert one â€“ maybe in the form of a 1px image hidden away by using inline style attributes. This is usually not too much to ask for, considering that pages are either made up of spacer GIFs or CSS documents, usually loaded from within the same domain. The static resources I mentioned could even be from a different sub-domain within the same domain, but it might complicate scripts slightly to have it set up that way. If this setup is not possible at all (oh, come on!), you could still find a work around2, but I think that this is the easiest way to get things up and running.
Now, let’s go over the process of actually orchestrating the communication.
The API client library is included on the page by means of a script tag pointing to your domain (your domain being the host of the client library). This is similar to including the Google Maps API on the page.
Once included, the script scans the page for the static resource mentioned above. This is done by walking the DOM looking for
imgtags, and checking the value of the
srcattribute to ensure it lies within the same domain as the calling page. The URL of this resource is stored for use later. At this point, if required, the client library can signal to the developer that it is ready for communication with the server. If the resource is not found, the client-library should throw an error and terminate.
When a request requires to be made, the client library takes the request parameters and prepares the markup for a form. This form can have any
methodattribute value, and should have it’s
actionattribute set to the proxy page on your domain. The parameters to be sent to the server should be enumerated as hidden fields within the form. The client library also specifies the resource (in a RESTful sense) that needs to be acted upon. Also, the name of the static resource we had hunted down earlier is passed on to the server. This form is not appended to the document yet. This markup is then wrapped into
<body>tags. The body tag should have
The client library then creates a 0px x 0px iframe, without setting the
srcattribute, and appends it to the page’s DOM. This makes the browser think that the iframe exists in the same domain as the calling page. Then, by using the iframe document object’s
close()methods the markup created in the previous step is dumped into the iframe. As soon as the close method is called, the form gets submitted to the proxy page on your domain because of the
onloadin the body tag. Also note that this gives the server access to any cookies it might have created from within it’s domain, letting you do things like authentication. In this way one part of the communication is complete, and the data has been sent to the server across domains. However, the iframe’s
document.domainhas now switched to point to your domain. The browser’s security model now prevents any script access to most parts of the iframe.
The proxy page sitting on your server now queries your REST API â€“ basically doing it’s thing â€“ and gets the response. Response in hand, the proxy is now ready to flush the response to the client.
If the response is rather large in size, as might be the case with a huge GET call for instance, the proxy breaks it up into chunks of not more than say 1.5 kb2.
The proxy is now ready to flush the response. The response consists of iframes â€“ one iframe for each of these 1.5 kb chunks. The iframe’s
srcattribute is set to the static resource we had discovered earlier. It is for exactly this purpose that we had hunted the resource down and passed on the URL to the server. At the end of each of these URLs, the proxy appends one of the chunks of the response, after a â€œ#â€ symbol, so that it works as a URL fragment identifier. Also, the iframe tags are each given a
nameattribute, so that the client script can locate them.
Meanwhile, the client-side code is where it had left off at the end of step 4 above. The script then starts polling the iframe it created to check for the existance of child iframes. This check of iframes will need to based on the iframe name the server will be sending down. It will look something like this:
window.frames.frames[â€œgrandChildIframeNameâ€]. Since the static resource we have loaded into the grandchild iframe is of the same domain as the parent page, the parent page now has access to it, even the intermediate iframe is of a different domain.
The client script now reads the
srcattributes of the iframe, isolates the URL fragments (
iframe.location.hash), and reassembles the data. This data would typically be some JSON string. This JSON can then be eval’d and passed on to a success handler. This completes the down-stream communication from the server to the client, again across domains.
With the entire process complete, the client-library can now perform some cleanup actions, and destroy the child iframe it created. Though leaving the iframe around is not a problem, it is not necessary and simply adds to junk lying around in the DOM. It’s best to get rid of it.
Posted by Dion Almaer at 8:46 am