patternjavascriptModerate
ETag Generation: Weak vs Strong and When Each Applies
Viewed 0 times
etagstrong etagweak etagcache validationconditional getif-none-match
Problem
Generating ETags incorrectly leads to unnecessary cache busting or, worse, serving stale content when the resource actually changed.
Solution
Strong ETags guarantee byte-for-byte identity. Weak ETags (W/"...") guarantee semantic equivalence. Use strong ETags when byte equality matters (Range requests), weak ETags for semantically equivalent representations.
import crypto from 'crypto';
// Strong ETag: hash of exact bytes
function strongEtag(buffer) {
return '"' + crypto.createHash('md5').update(buffer).digest('hex') + '"';
}
// Weak ETag: based on logical version
function weakEtag(version) {
return 'W/"' + version + '"';
}
// In Express
app.get('/file', (req, res) => {
const data = readFile();
const etag = strongEtag(data);
res.setHeader('ETag', etag);
if (req.headers['if-none-match'] === etag) return res.sendStatus(304);
res.send(data);
});Why
Range requests require strong ETags because the server must guarantee the bytes haven't changed between requests for different byte ranges of the same resource.
Gotchas
- ETags must survive server restarts if you want cross-instance cache validation — don't use process-memory counters.
- Gzip encoding changes bytes, so a strong ETag changes after compression — use Vary: Accept-Encoding.
- Express sets ETags automatically for
res.send()using a weak ETag by default.
Revisions (0)
No revisions yet.