Tuesday, 15 May 2007
Expires vs. max-age
I occasionally get a question from readers of the caching tutorial about whether to use the Expires header or Cache-Control: max-age to control a response’s freshness lifetime.
Some people claim that Expires is better, because it’s defined by HTTP/1.0, whereas Cache-Control only came about in HTTP/1.1. Since there are still HTTP/1.0 agents out there, the reasoning goes, this is the safer path.
The problem with that line of reasoning is that HTTP versions aren’t black and white like this; just because something advertises itself as HTTP/1.0, doesn’t mean it doesn’t understand HTTP/1.1 (see RFC2145 for more). In fact, since Cache-Control was one of the earlier mechanisms in HTTP/1.1, virtually every cache implementation out there understands max-age, whatever version of HTTP they advertise.
So, this puts the two on even footing. What tips the scales in favour of Cache-Control: max-age is its relative simplicitly. Consider:
as opposed to
Expires: Tue, 15 May 2007 07:19:00 GMT
CC: max-age is just a straight integer number of seconds, while Expires has a somewhat complex date format. From what I’ve seen in various implementations, this makes a difference; even small errors in generating the Expires value (e.g., omitting the leading ‘0’ from the hour) can cause downstream caches to misinterpret it. It happens more often than you think.
Compounding these errors are the caches themselves; in testing a variety of commercial and open source implementations, I found that a large number flout this requirement;
HTTP/1.1 clients and caches MUST treat other invalid date formats, especially including the value “0”, as in the past (i.e., “already expired”).
…which means that an errors you make might have unpredictable results, potentially allowing your response to be cached for longer than you intended.
Furthermore, if you forget to update your Expires time, or get the time zone conversions wrong (source of many an error), you’ll end up with unpredictable results as well.
So, my recommendation is to either use a well-tested library (e.g., mod_expires) to generate both Expires and Cache-Control: max-age for you, or to only generate CC: max-age if you’re doing it yourself, to reduce the chance of messing things up.