The cached copy is still valid.
When to use it
Answering a conditional request with If-None-Match or If-Modified-Since.
Good to know
304 answers a conditional request. When a response carries an ETag or Last-Modified header, the browser later sends If-None-Match or If-Modified-Since, and the server replies 304 with no body if nothing changed, saving bandwidth. A 304 should repeat headers such as ETag, Cache-Control and Vary, so the cache can refresh its stored copy and its expiry time.
ETags generated per machine, such as Apache’s old inode-based ones, differ between servers behind a load balancer, so clients rarely get 304. Compression can also change or weaken ETags. In DevTools a 304 transfers a few hundred bytes, while “from disk cache” with status 200 means no request was made at all. fetch hides browser revalidations and reports them as 200 with the cached body.
Redirection (3xx)
3xx codes are redirections: the client has to go somewhere else, or use its cached copy, to finish the request.
What it looks like
HTTP/1.1 304 Not ModifiedHow to send it
| Node.js / Express | res.status(304).end() |
|---|---|
| Python / Flask | return '', 304 |
| nginx | return 304; |
How to check it
curl -s -o /dev/null -w "%{http_code}\n" https://example.com/