The course
Caching & Vary
Two distinct caching lessons. First: a passed preflight is expensive,
so the browser remembers it — repeat the same request and the
OPTIONS round trip is silently skipped for a while. Second:
a shared cache (a CDN, a platform edge) sitting in front of an
origin-reflecting API can leak one visitor’s authorised response
to another unless it varies on Origin. The probe below
measures the first one live; the second is simulated, because no real
shared cache sits in front of this demo API.
The preflight cache, measured live
Press Run series to fire 5 identical cross-origin PUT requests at one fixed URL and count how many OPTIONS preflights the server actually received. The browser decides on its own whether to reuse a cached preflight — the counts below come from the server's own record.
Vary: Origin — the shared-cache trap
The demo API reflects the requesting origin back in
Access-Control-Allow-Origin (an allowlist-gated match,
never a blind echo). That is the correct, safe pattern for a
single-origin API. But put a shared cache between the browser and that
API — a CDN keyed on URL alone — and the cache will happily store one
visitor’s ACAO: https://app-one.example response and
serve it to a different visitor whose origin is
https://app-two.example. The second visitor’s browser
then reads an ACAO that does not match its own origin and
blocks the read: one user’s authorisation leaked into
another’s request. Vary: Origin is the header that
prevents it — it instructs the cache to keep each origin’s entry
separate.
Step through the simulated version below. It is labelled simulated because, again, no real CDN sits in front of this API — the failure it walks through is a real production trap that a single-origin lab cannot reproduce live.
Simulated — no real CDN sits in front of this API
A shared cache (a CDN, a platform edge) that keys only on URL will hand one visitor’s authorised response to a different visitor whose origin the server never approved. Vary: Origin is the fix — it tells the cache to keep each origin’s entry separate. This widget steps through the failure with two fictional origins; no real request leaves your browser.
Simulated CDN cache slot
empty — nothing cached yet
Press “Replay https://app-one.example’s request” to populate the cache.