Conditional requests are HTTP’s built-in bandwidth refund: the client says what version it holds, the server answers 304 Not Modified, and no body crosses the wire. The machinery is elegant, widely implemented, and broken in a remarkable share of production estates for reasons that fit on one page.
Validators, strong and weak
An ETag is an opaque version identifier; Last-Modified is its timestamp cousin with one-second granularity. Strong ETags assert byte-for-byte identity and permit byte-range reuse; weak ETags (W/ prefix) assert semantic equivalence only. Clients revalidate with If-None-Match against ETags, If-Modified-Since against timestamps, and ETags win when both are present. Emit both when cheap; ensure at least one is honest.
How estates break them
The classic: load-balanced origins generating different ETags for identical content, default ETag algorithms incorporating inode numbers or per-machine state, so every revalidation misses and refetches. The compression variant: some stacks alter response bytes per encoding without adjusting the strong ETag, technically violating identity. The deployment variant: builds that regenerate mtimes on every deploy, invalidating Last-Modified across the entire asset base for no content change. Each produces the same symptom: 200s where 304s should live.
The interaction with modern immutable-asset practice deserves clarity, because teams over-rotate: fingerprinted assets with year-long max-age and immutable never revalidate, so their ETags are vestigial, harmless but idle. Validators earn their keep on the mutable remainder: HTML documents, APIs, media manifests, anything with short TTLs and real change rates. That remainder is precisely where a working 304 pipeline slashes both perceived latency (revalidation round-trips carry no body) and origin egress, and where a broken one silently doubles your transfer bill. Point the audit at the mutable paths; the immutable ones already graduated.
The CDN’s role
A good CDN revalidates on your behalf: it holds the object, forwards conditional requests upstream, and refreshes its copy on 304 without re-downloading, meaning origin bandwidth for unchanged objects rounds to headers. Verify yours actually does this, and that your origin honors conditionals rather than ignoring If-None-Match and streaming full bodies, a dismayingly common misconfiguration that turns the entire mechanism into decoration.
In practice
Test with curl this afternoon: fetch a static asset, replay with If-None-Match set to the returned ETag, and confirm a 304 with empty body, from the edge and from origin directly. Fix content-derived ETags (hash the bytes, not the metadata) on multi-origin fleets. Then watch the ratio of 304s to 200s on revalidatable content as a standing metric; it is the honesty score of your validator pipeline.
Our performance audits include a validator honesty check across your top paths. It fails more often than anyone expects.
