HTTP 304 Not Modified — What It Means & How to Debug
HTTP 304 Not Modified indicates the cached version of a resource is still valid — the server tells the client to use its local cached copy without re-downloading.
What It Means
The HTTP 304 Not Modified status code is a caching response. It tells the client that the requested resource has not changed since the last time it was fetched. Instead of re-sending the full resource, the server responds with 304 and an empty body, instructing the browser to use its locally cached copy.
This status code is only returned when the client sends conditional headers — If-Modified-Since or If-None-Match — that include the last modified date or ETag from a previous response. The server compares these values against the current resource state and returns 304 if nothing has changed.
When It’s Sent
- Browser refreshing a page with cached assets (CSS, JS, images)
- API clients sending
If-None-Matchwith stored ETags - Proxy and CDN revalidation checks
- Browser navigating back/forward through history
- Static file servers returning unchanged files
Real Example
curl -v https://example.com/style.css \
-H "If-Modified-Since: Fri, 20 Jun 2025 10:00:00 GMT"Expected response if the file hasn’t changed:
> GET /style.css HTTP/1.1
> Host: example.com
> If-Modified-Since: Fri, 20 Jun 2025 10:00:00 GMT
>
< HTTP/1.1 304 Not Modified
< Date: Fri, 20 Jun 2025 12:00:00 GMT
< ETag: "abc123"
< Cache-Control: max-age=3600
<No file content is sent — the response body is empty and the browser uses its cached style.css.
How to Debug
Browser DevTools
- Open the Network tab
- Reload the page
- Look for requests with status
304in the Size column (often shows “from disk cache”) - Click the request and check the Headers tab for
If-Modified-SinceandIf-None-Matchin Request Headers - The Response Headers show
304confirming the cached version is fresh
curl
# First request to get the ETag
curl -I https://example.com/script.js
# Look for the ETag header in the output, then use it:
curl -I https://example.com/script.js \
-H "If-None-Match: \"abc123\""If the resource hasn’t changed, the response is 304 Not Modified with no body.
Postman
Send a GET request and note the ETag or Last-Modified header in the response. Then send the same request with the If-None-Match header set to that ETag value. The response changes from 200 to 304.
How to Fix
If caching behavior seems wrong:
- Server-side: Ensure your server sends
ETagorLast-Modifiedheaders — without these, the client can’t send conditional requests - Cache-Control: Set appropriate
Cache-Controlheaders —max-agetells the client how long to cache before revalidating - Weak ETags: If using weak ETags (prefixed with
W/), the server checks semantic equivalence, not byte-for-byte identity - Static files: For Nginx, ensure
etag on;is in the config; Apache enables ETags by default for static files - Force refresh: Hold
Ctrl(Cmd on Mac) while clicking reload to bypass cache and force a full re-download
Common Causes
| Scenario | What Happens | Why It Matters |
|---|---|---|
| Page reload | CSS/JS files return 304 if unchanged | Page loads faster from cache |
| Browser history | Navigated pages return 304 | Instant back/forward navigation |
| API polling | Client sends ETag and gets 304 | Reduces bandwidth and server load |
| CDN revalidation | Edge node checks origin with If-None-Match | Keeps cached content fresh |
| Image gallery | Viewed images return 304 on re-visit | Faster gallery navigation |
FAQ
Related Codes
- HTTP 200 OK — the server returns the full resource when it has changed
- HTTP 301 Moved Permanently — the resource has moved, cache the new URL
- HTTP 412 Precondition Failed — conditional headers don’t match server state
- HTTP 404 Not Found — the previously cached resource no longer exists
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro