Skip to content
AITroveRead. Build. Understand.
Make this comfortable

HTTP caching: validate a changed representation with an ETag

Last updated: 4 Oct 20266 min read
tutorial
IntermediateBy AITrove Editorial

Caching is a contract about freshness and reuse, not an instruction to store every response forever. A server can attach an entity tag to a representation. On a later read, the client can send If-None-Match; a matching current tag lets the server return 304 without sending that representation body. A changed representation needs a new tag and a normal response body. Cache-Control sets the reuse policy and is especially important for personalized data. The compact model below hashes the exact text used as the representation and compares a supplied validator. A real HTTP implementation must also handle weak validators, content negotiation, authentication, and the correct response headers.

Case study

A public maintenance notice first contains 'Valve review pending'. The client stores its tag. The next read supplies the same tag and gets 304 with no body. After the notice changes to 'Valve review complete', its tag differs and the client receives 200 with the new text. A personalized inspection queue should use a privacy-aware cache policy rather than being treated like a public notice. A 304 is meaningful only when the client already has a reusable representation; it is not a substitute for the first response.

Working contract

javascript
const { createHash } = require("node:crypto");
function serveNotice(text, ifNoneMatch) {
  const etag = `"${createHash("sha256").update(text).digest("hex")}"`;
  if (ifNoneMatch === etag) return { status: 304, etag, body: null };
  return { status: 200, etag, body: text };
}
const first = serveNotice("Valve review pending");
const unchanged = serveNotice("Valve review pending", first.etag);
const changed = serveNotice("Valve review complete", first.etag);
console.log(first.status, unchanged.status, changed.status);
console.log(unchanged.body === null, changed.body);

Observed output

Output
200 304 200
true Valve review complete

Cost and tradeoffs

Hashing a representation of B bytes is O(B) time; storing the current notice is O(B) space. Comparing fixed-length tags is O(1) after the tag is computed. A 304 can save roughly B response-body bytes, though headers and request latency remain. Computing a hash on every request may itself be expensive for a large generated page; a service can cache a version token when the underlying content changes. A CDN or shared cache also needs correct variation and privacy rules so one user's body never appears in another user's response.

Common Mistakes

  • Do not send 304 if the representation changed.
  • Do not give a public shared cache a private user's page without a safe policy.
  • Do not assume a validator removes request latency.
  • Do not vary the body by language or authorization while reusing one tag carelessly.

Continue through the stack

HTTP requests: keep method, status, and body contracts separate; Page loading: keep content available while CSS and scripts arrive; Page performance: budget the critical path and reserve layout space.

Broader connections

Service Worker Offline Fallback; Canonical Route Identity.

Failure trace

The browser shows an old case after an update because the response was treated as fresh for too long. The team then disables every cache, increasing transfer without fixing the private-data policy. Give representations an appropriate cache rule and validator; a stale client can send If-None-Match and receive 304 when the current representation is unchanged, or 200 with a new body when it changed.

Verification

  • Read a case, repeat with its validator, and confirm an unchanged response omits the full body.
  • Change the record, repeat the conditional request, and confirm the new representation arrives.
  • Use two accounts and verify a private cached response is never shared across them.

Decision note

A validator avoids retransmitting unchanged bytes but still costs a request and server comparison. Choose freshness duration, privacy policy, and invalidation from the data contract rather than applying one setting to all pages.

Further connections

Conditional Writes and Lost-Update Prevention.

Further connections

Server Data Bootstrap and Freshness; Client Cache Keys and Invalidation.

Further connections

HTTP Delivery and Cache Ownership; Shared Cache Keys and Private Response Boundaries; Stale Revalidation and Versioned Purges.

web-tech
web-development
Storage details