"Track 2 taught you the conditional request semantics. This lesson is the same mechanism through the eyes of CDNs, browsers, and your own client — how the bytes you DON'T send add up to real cost savings at scale."
The Caching Layer's Star Trick
Conditional GET (introduced in Track 2 Lesson 4) is THE optimization that powers every CDN, browser cache, and reverse proxy. The pattern:
- First request returns body + ETag + Cache-Control.
- Cache stores the response.
- After max-age expires, the cache doesn't refetch the full body — it sends a conditional GET with
If-None-Match: "<etag>". - If server's ETag matches, server returns
304 Not Modified— NO body, just "your copy is good." - Cache refreshes its TTL and continues serving the stored body.
The win: bandwidth proportional to body size, completely avoided. For a 500KB JSON catalog refetched every 60 seconds across 10,000 active clients, that's potentially 5 GB/minute of network not used.
The Three Layers That Coordinate
A typical request crosses three caches, each running this protocol:
- Browser cache — per-user, stores responses with Cache-Control. Replays without network when fresh; conditional GETs when stale.
- CDN edge — shared across users in a region. Stores responses with Cache-Control: public. Conditional-GETs origin when stale.
- Reverse proxy / origin — closest to the application. Often also a cache (Cloudflare Workers, Vercel Edge Config, Nginx microcache).
Each layer uses the same conditional-GET protocol with the layer below. Origin still sees periodic conditional GETs from the CDN, but the CDN absorbs the user-facing traffic. The bandwidth savings multiply.
What Makes a Good Validator
ETag is the validator most caches prefer. Three ways to compute it:
- Content hash — sha256 of the serialized body. Exact: any byte change → new ETag. Cost: hash the body on every response.
- Version field — if your resource has an
updated_attimestamp or version counter, use it directly:ETag: "v17-1716623210". Free to compute; relies on you bumping the version on every update. - Composite hash — combine the resource version with serialization-relevant inputs (locale, fields selected). Necessary when content negotiation can produce multiple bodies from one resource.
Weak ETags (W/"v17") signal "semantically equivalent, byte-different." Useful when minor serialization differences shouldn't bust the cache. Strong ETags are the default.
The 304 Response in Detail
A 304 response MUST include the validator headers (ETag, Last-Modified) so the cache can refresh its entry. It SHOULD also include any Cache-Control directives that changed (the cache extends its TTL based on these). It MUST NOT include a body.
HTTP/1.1 304 Not Modified
ETag: "v17-abc123"
Last-Modified: Sun, 25 May 2026 03:00:00 GMT
Cache-Control: public, max-age=60
Vary: Accept-Encoding, Authorization
(no body)
The lack of body is the entire savings. Clients that always call response.json() will crash on 304 — the body length is zero. Real HTTP clients (browsers, httpx, fetch) handle this transparently by serving the previously-cached body when a 304 comes through.
The Common Gotchas
1. Non-deterministic serialization. If your server's JSON output isn't byte-stable (key order varies, timestamps change), the hash-based ETag changes every request and the 304 path never fires. Sort keys; round timestamps; use stable serialization.
2. Forgetting Vary. If your response varies by Accept-Encoding (gzip/br) or Authorization, the cache must know — without Vary, user A's compressed authenticated response gets served to user B asking for plain.
3. Caching auth-required responses with public. Only mark public if the response is truly the same for all users; for per-user responses, use private + ETag for client-side cache + conditional-GET wins without CDN exposure.