304 Not Modified
The copy the client already has is still current, so the server sends headers only.1 It answers a conditional GET or HEAD: one that carries If-None-Match or If-Modified-Since.
- Class 3xx redirection
- Body none
- Headers ETag, Last-Modified
Open Hash Generator An ETag is often a hash of the content.
When you see it
- The browser revalidates a cached file whose
max-ageran out, sending theETagit stored asIf-None-Match. - A CDN or proxy checks its copy against the origin.
- You pressed reload: browsers revalidate the page itself even while it is still fresh.
What to check
- A 304 is a success. If your code treats it as an error, the HTTP client isn't handling conditional requests; browsers and
fetchhand you the cached body with status 200.2 - Stale content despite 304s means the validator didn't change when the content did. An
ETagbuilt from file size and modification time can survive a deploy; a hash of the content can't. - A proxy that compresses on the fly may rewrite the ETag (Apache adds
-gzip)3 or drop it. ThenIf-None-Matchnever matches, and every request costs a full 200: compare the ETag the client stores with the one the origin checks. - Files with a content hash in their name (
app.3f9a1c.js) don't need revalidation at all: serve them withCache-Control: max-age=31536000, immutable.4
304 or a 200 from cache?
A 304 costs a round trip to the server, just without the body. A fresh cached response (DevTools shows "from disk cache") costs no request at all. max-age decides which of the two you get.
304 or 412?
Both answer a conditional request. If-None-Match on a GET gets a 304 when nothing changed. If-Match on a PUT gets a 412 when something did,5 which is how APIs stop lost updates.
Example
GET /app.css HTTP/1.1 Host: example.com If-None-Match: "33a64df551425fcc55e4d42a148795d9f25f89d4" HTTP/1.1 304 Not Modified ETag: "33a64df551425fcc55e4d42a148795d9f25f89d4" Cache-Control: max-age=3600
Sources
- 1 RFC 9110, HTTP Semantics, section 15.4.5. rfc-editor.org ↩︎
- 2 Fetch Standard, HTTP-network-or-cache fetch. fetch.spec.whatwg.org ↩︎
- 3 Apache HTTP Server, DeflateAlterETag. httpd.apache.org ↩︎
- 4 RFC 8246, HTTP Immutable Responses, section 2. rfc-editor.org ↩︎
- 5 RFC 9110, HTTP Semantics, section 13.1.1. rfc-editor.org ↩︎