MockFoxAdvertise

HTTP 304 Not Modified

Updated Free mock REST & WebSocket APIs

HTTP 304 Not Modified — The cached copy the client already has is still valid, so no body is sent.

Class
3xx Redirection
Defined in
RFC 9110 §15.4.5
Official
Yes (IANA registry)
Cacheable by default
No (unless Cache-Control/Expires say so)

Try it: get a real 304 response

Our test endpoint answers every request with 304 Not Modified.

curl -i https://mockfox.dev/api/status/304

Use it in tests, health-check monitors or to see how your client handles a 304. Add ?delay=2000 to slow it down.

What does HTTP 304 mean?

304 Not Modified is the server's answer to a conditional request when the client's cached copy is still current. It has no body: the client reuses what it already has, saving bandwidth and time.

Browsers make these requests automatically. When a cached response has an ETag, they send If-None-Match: <etag>; when it has Last-Modified, they send If-Modified-Since: <date>. If nothing changed, the server replies 304 with refreshed caching headers.

When is 304 used?

  • Revalidating cached HTML, CSS, JS or images after their max-age expired.
  • API clients polling a resource with If-None-Match to detect changes cheaply.
  • CDNs revalidating their cached copy with the origin.

Why you're seeing 304

  • Normal caching — it's a performance win, not an error.
  • If you see stale content after a deploy, the server may be generating identical ETags/Last-Modified for changed files, or the HTML references un-fingerprinted asset URLs.

What to do about 304

If you're visiting the site

  1. Nothing to fix. If a page looks outdated, do a hard refresh (Ctrl+Shift+R / Cmd+Shift+R), which bypasses the cache.

If you run the site or API (developers)

  1. Send a strong ETag or accurate Last-Modified on cacheable responses — Express and nginx do this for static files by default.
  2. Fingerprint static assets (app.3f9a1c.js) and cache them with Cache-Control: public, max-age=31536000, immutable so they never need revalidation.
  3. A 304 must not include a body, and should repeat headers like ETag, Cache-Control and Vary that would be sent with the 200.
  4. In fetch(), a 304 from the browser cache surfaces as a 200; you'll only see 304 in DevTools or when you send conditional headers yourself.

Sending 304: server examples

nginx

location /static/ {
    etag on;               # default
    expires 1y;
    add_header Cache-Control "public, immutable";
}

Express

// res.send() computes a weak ETag and answers 304 automatically
// when the request's If-None-Match matches (req.fresh === true).
app.get("/api/config", (req, res) => {
  res.set("Cache-Control", "no-cache"); // always revalidate
  res.json(config);
});

Next.js

// app/api/example/route.ts (Next.js App Router)
export async function GET(req: Request) {
  const { data, etag } = await getConfig();
  if (req.headers.get("if-none-match") === etag) {
    return new Response(null, { status: 304, headers: { ETag: etag } });
  }
  return Response.json(data, { headers: { ETag: etag, "Cache-Control": "no-cache" } });
}

Example 304 response

HTTP/1.1 304 Not Modified
ETag: "33a64df551425fcc55e4d42a148795d9"
Cache-Control: max-age=3600
Date: Sun, 18 Oct 2026 10:00:00 GMT

Related status codes

Related tools

Frequently asked questions

Is 304 Not Modified an error?

No. It's a successful revalidation that tells the client to use its cached copy.

Does 304 affect SEO?

It helps crawl efficiency: Googlebot sends conditional requests and a 304 tells it nothing changed. Just make sure changed pages actually return 200 with the new content.

What's the difference between 304 and 200 (from cache)?

"200 (from disk/memory cache)" in DevTools means the browser didn't contact the server at all because the cached copy was still fresh. 304 means it asked the server, which confirmed the copy is still valid.