posted on Saturday, June 12, 2004 1:55 PM by leon

Solving client resources caching problem

Let's get back to the old client caching problem.

Consider the following scenario:
We have a web based application that contains static client resources (*.js, *.css, *.htc etc). We would like to exploit downstream cache, and be absolutely sure that the client receives up to date file version. Possible solutions are:
1. Play around with cache expiration header. Yuri had just posted the right way to do it. In case that the client's request had reached the server, the resource expiration date will be checked, and the updated resource or 304 (not changed) will be served. The main disadvantage of this method is a need for a client to make a roundtrip on each access to the resource. Even if we completely control all clients and make them ask for a new version of file on every visit (Settings of IE), we will still have to trust that all proxies between our client and IIS are playing nice and are not just checking against their own local cache. Even if we did manage to ensure all this, we will still get roundtrip on every visit to everything! Having not-so-wide connection, this can result in flickering and unnecessary server load.
2. Change resource URL with every update. Advantage is clear. It is absolutely bullet proof. You can use the most aggressive caching mechanism and still be sure resource is OK. Browser will have to go the whole way because the item with a new URL is not found anywhere. Unfortunately, disadvantage is also clear: It's a hell to support such a deployment scenario.
3. Whidbey client resource caching approach.
4. Any other ideas?


Whidbey is not here yet for a while, and we have variety of ASP.Net systems out there in production. What can we do today (that is better than instruct our clients to clear browser cache each time the problem occurs)?
We would like to change URL but don't want to deploy changes differently. Let's steal some Whidbey ideas. We will construct some mechanism that automatically modifies resource URL on each update. On the server side we'll use custom HTTP handler to map modified URL to real file.


Let's start with URL creation. It will be constructed as <original_file_name>_<version>_<content_type>_InfraScriptCache.js. First of all we will use version indicator from Web.config file to automatically modify URL. Pay attention to resource extension. It appears that majority of browsers don't trust unknown file extensions, and if the browser doesn't trust something, it will travel to server to check and to be on the safe side. To prevent it we let the browser treat all resources as js files and incorporate real content type into resource URL.  Extending URL with "_InfraScriptCache.js" is our way to let custom handler know it should process this request. We don't want occasional js files receive special treatment.
Now let's look at HTTP handler. It is really simple. The handler has to do just a couple of things:
1. Check "If-Modified-Since" header. If it exists in request, browser has the right version and is checking for updates. There is no change in version number, no need to proceed, just to serve 304 to client.
2. If "If-Modified-Since" is not here, browser is looking for updated/new file for the first time. Now we read the file, optionally in-memory cache it, set expiration date to a year from now (some browsers will disregard longer expiration period), and serve file.
Having both ends, all we have to do is setup Http handler on IIS (one time installation), and update version indicator in Web.config on each resource update.

Article with the whole source code is here for now. I'll try to upload it tomorrow in more readable form.

Comments