Fixing Chrome’s AJAX Request Caching Bug
- by Steve Wilkes
I recently had to make a set of web pages restore their state when the user arrived on them after clicking the browser’s back button. The pages in question had various content loaded in response to user actions, which meant I had to manually get them back into a valid state after the page loaded. I got hold of the page’s data in a JavaScript ViewModel using a JQuery ajax call, then iterated over the properties, filling in the fields as I went. I built in the ability to describe dependencies between inputs to make sure fields were filled in in the correct order and at the correct time, and that all worked nicely. To make sure the browser didn’t cache the AJAX call results I used the JQuery’s cache: false option, and ASP.NET MVC’s OutputCache attribute for good measure. That all worked perfectly… except in Chrome. Chrome insisted on retrieving the data from its cache. cache: false adds a random query string parameter to make the browser think it’s a unique request – it made no difference. I made the AJAX call a POST – it made no difference. Eventually what I had to do was add a random token to the URL (not the query string) and use MVC routing to deliver the request to the correct action. The project had a single Controller for all AJAX requests, so this route: routes.MapRoute(
name: "NonCachedAjaxActions",
url: "AjaxCalls/{cacheDisablingToken}/{action}",
defaults: new { controller = "AjaxCalls" },
constraints: new { cacheDisablingToken = "[0-9]+" });
…and this amendment to the ajax call:
function loadPageData(url) {
// Insert a timestamp before the URL's action segment:
var indexOfFinalUrlSeparator = url.lastIndexOf("/");
var uniqueUrl =
url.substring(0, indexOfFinalUrlSeparator) +
new Date().getTime() + "/" +
url.substring(indexOfFinalUrlSeparator);
// Call the now-unique action URL:
$.ajax(uniqueUrl, { cache: false, success: completePageDataLoad });
}
…did the trick.