Wednesday, October 06, 2010

IE Cache and AJAX: Cache Busting Ajax requests

Yet another 'special case' caveat for Internet Explorer, the red headed step child of the browser family..... (sorry to any red headed step children who might be reading this - chalk it up to the savage injustices of life). I discovered that IE cache and Ajax requests are not the best of friends compared to how other browsers handle Ajax requests.



Recently I found that IE cached ajax requests in a CodeIgniter + ExtJS site. I was using url rewriting, so all GET params were encoded as URI segments...

eg. (http://host/controller/action/param1/param2)

The Problem:
Usually, I would use ExtJS inherent cache busting tools (Ext.Ajax.disableCaching - which normally defaults to true).... but due to the url rewriting, the ExtJS method caused issues. Query string values (?blah=value) are disallowed in my app due to the url rewriting, therefore EXTs native cache disabling does not work as it simply appends a uid to the querystring (?_dc=123453443343). This caused 'disallowed character' exceptions.

Furthermore - I couldn't simply add a random variable to the end of a request, as this could be misinterpreted as an actual parameter for actions with parameters with default values

eg. http://host/controller/action/param1/param2/no_cache01223213312

no_cache01223213312 could be misinterpreted as param3 in the following action:
public function action($param1, $param2, $param3 = "default value")
{
//..//
}


The Solution:
The Big Stick:
Whether you use an MVC framework, URL rewriting, the first thing you should consider is that on all Ajax actions, make sure the header 'pragma' is set to no-cache..... so in php - write the header somewhere before content is returned to the browser

header("Pragma: no-cache");

This can really suck as it blows away all your lovely server side cache introducing a potential performance bottleneck to your app, all because Dwayne Dibley is still browsing your site using IE.

The ExtJS (Javascript) way:
The Ext solution was at the page level to intercept all AJAX requests, and add a random POSTED variable to the parameter listing.


Ext.Ajax.disableCaching = false;
Ext.Ajax.addListener("beforerequest", function (conn, options ){
   if(!options.params) options.params = {};
   options.params.cacheBuster = Ext.id();
}, this);



This forces a server side request as the request is unique (thanks to the random post variable). It also allows me to free specify GET params in the rewritten url, as I am adding a POST variable to uniquify the request.

For generic javascript.... when calling the target url, simply append a generated dummy query string parameter (like a timestamp)

"http://myhost.com/myAjaxPage.php?_nocache=321313213445462"

Again, the same caveat applies to the pragma header - you would probably want to make this cache busting parameter conditional on browser type

3 comments:

Anonymous said...

Thanks, it works!

Anonymous said...

It's really helpful. Nice post!!Thanks!

Randall said...

Thanks