Skip to content
GreenSnippets

Conditional GET with ETag and 304

Compute a strong ETag for a response body and answer If-None-Match with 304 Not Modified to save bandwidth.

JavaScript
import { createHash } from "node:crypto";

function makeEtag(body) {
  const hash = createHash("sha256").update(body).digest("base64url").slice(0, 27);
  return `"${hash}"`;
}

function isNotModified(ifNoneMatch, etag) {
  if (!ifNoneMatch) return false;
  if (ifNoneMatch.trim() === "*") return true;
  return ifNoneMatch.split(",").some((tag) => tag.trim().replace(/^W\//, "") === etag);
}

function respond(request, body) {
  const etag = makeEtag(body);
  const headers = { ETag: etag, "Cache-Control": "no-cache" };
  if (isNotModified(request.headers.get("if-none-match"), etag)) {
    return new Response(null, { status: 304, headers });
  }
  return new Response(body, { status: 200, headers });
}

Example / expected output

Output
// First request: 200 with ETag. Next request with If-None-Match: 304, empty body.

How it works

An ETag is a fingerprint of a representation. Clients send it back in If-None-Match; if it still matches, the server replies 304 with no body. The comparison must tolerate a list of tags and the * wildcard. This sketch uses Node's crypto, and the same idea works in any framework.