HTTP conditional caching: ETags and the 304 response
Cloud Computing's CDN lesson covered Cache-Control headers telling a cache how LONG to keep something. A separate, complementary mechanism handles what happens once that time is up — letting a client ask "is my copy still good?" and get a one-word answer, instead of re-downloading the whole thing just to find out.
Intermediate
3 min read
The problem a plain TTL expiration creates
A Cache-Control: max-age=3600 response (covered from the CDN's perspective in Cloud Computing) tells a browser or CDN to treat a cached response as fresh for one hour. Once that hour passes, the naive behavior is a full re-fetch — re-downloading the entire resource even if it hasn't actually changed at all, which wastes bandwidth and server work for the overwhelmingly common case of "nothing changed since last time."
ETags: a fingerprint of the current content
Server response includes:
ETag: "a1b2c3d4e5f6"
An ETag (entity tag) is a short, opaque identifier the server generates from a resource's current content — often a hash of the content itself, so identical content always produces the same ETag and any change to the content produces a different one. It's a fingerprint, not a version number a human would read meaningfully.
The conditional request: "only send me the full response if this fingerprint is stale"
Once a client's cached copy's freshness window expires, instead of blindly re-fetching, it sends the ETag it already has back in an If-None-Match header. The server compares that ETag against the resource's current content: if they match, nothing has changed, and the server replies 304 Not Modified with no response body at all — confirming the client's existing cached copy is still correct, at a fraction of the cost of re-sending the entire resource. If they don't match, the server sends the full 200 OK response with the new content and a new ETag.
Last-Modified and If-Modified-Since: the older, coarser alternative
An older, still-common mechanism does the same thing using a timestamp instead of a content fingerprint: the server sends Last-Modified: <timestamp>, and a client's follow-up request includes If-Modified-Since: <that timestamp>. This is coarser than an ETag in one real way — it only has the resolution of whatever timestamp precision the server tracks, and can't distinguish "genuinely identical content" from "content technically re-saved at a new timestamp with no actual change," producing unnecessary 200 responses an ETag-based fingerprint would have correctly matched as unchanged.
Why this complements, rather than replaces, a TTL
A TTL (max-age) and conditional validation solve different halves of the same overall problem: the TTL controls how often a client even bothers asking the server anything at all (a client with a fresh, unexpired cache doesn't make a request in the first place); conditional validation controls what happens once that TTL has expired and a request does go out, making the common "nothing actually changed" case cheap instead of assuming a full re-fetch is the only option. Real systems use both together — a reasonably long TTL to avoid unnecessary requests entirely, and ETags to make the requests that do happen, once the TTL lapses, cheap when nothing changed.