Thursday, August 28, 2008

effective use of the expires header and client-side caching

There are two problems for web developers when it comes to client-side caching:
  1. The browser aggresively caches everything on your site, so the user doesn't see your new images, scripts, or stylesheets for days or weeks.
  2. The browser carefully checks for new images, scripts, and stylesheets on every page load.
So, there's one group of people who are seeing old content and another group of people bogging down your server, because their browser is carefully checking for updated files with each page load. It would be nice if you could just tell everyone and everything when to check for new content, wouldn't it be?

Well, to be quite honest, you can.

In fact, at its best, you would be telling every browser never to check for new images, scripts, and stylesheets. Don't be shocked--this is a good thing.

By doing this, you save on bandwidth and server resources. And when you need to roll out a new image, you just change the name, which forces all clients to download the new image! It can be as simple as adding a version number to the file or query string. For example,

logo.png -> logo.png?v=2 -> logo.png?v=3
In the example above, the file name stays the same, but you force the browser to check for an update with the query string.

If you can do this, you can rest assured that everyone is seeing up-to-date content, and your server is under a much lighter load.

The header tags you need to worry about look like this:
Cache-Control: max-age=259200
Expires: Thu, 01 Dec 1994 16:00:00 GMT

In general, if we assume your content should never expire, you need to set the date in this header to be one year from the time of file access, but no more per the W3 specs. There are two easy ways to do this. One, which I won't go into detail on, is serving all your images via a script, which allows you a lot of flexibility in many ways, including setting the expires and cache-control header.

The other way assumes you're using Apache, and it's very easy to do. It requires your Apache server have mod_expires enabled and either have access to your main configuration file or have .htaccess enabled. For most developers, mod_expires will be enabled by default, and if you don't have access to httpd.conf, you can probably use .htaccess.

So, it's as easy as adding the following lines to the end of your .htaccess or main config file (usually httpd.conf):
ExpiresActive On
ExpiresByType image/png "access plus 1 year"
ExpiresByType image/jpeg "access plus 1 year"

And so forth for each file type you wish to "force" caching on.

Doing this can save many sites a huge number of HTTP requests per page load--often reducing most page loads to the one HTTP request they should be. At the same time, you'll be forcing yourself to use "new" file names for updated content, effectively forcing everyone to see new images and styling exactly when you want.

Happy caching!

1 comment: