**Approach (brief)**Use Last-Modified (from a row's updated_at) and ETag (strong or weak) to let clients send If-Modified-Since / If-None-Match. On conditional GET: validate server-side; return 304 when unchanged; otherwise 200 with new body and headers.**Sequence of headers**- Cache miss (first GET): - Request: none - Response: 200 OK - Last-Modified: Tue, 02 Mar 2026 12:34:56 GMT - ETag: "v12345" (or weak: W/"hash") - Cache-Control: public, max-age=60- Cache hit (client conditional): - Request: If-Modified-Since: Tue, 02 Mar 2026 12:34:56 GMT If-None-Match: "v12345" - Response if unchanged: 304 Not Modified - ETag: "v12345" - (no body) - Response if changed: 200 OK (new body + updated Last-Modified, ETag)**Express example (Node.js)**javascript
// Express pseudo-code
app.get('/resource/:id', async (req,res)=>{
const row = await db.query('select data, updated_at, version from items where id=$1', [req.params.id]);
const last = row.updated_at.toUTCString();
const etag = `"${row.version}"`; // cheap surrogate
res.set('Last-Modified', last);
res.set('ETag', etag);
if (req.headers['if-none-match'] === etag || new Date(req.headers['if-modified-since']) >= row.updated_at) {
return res.status(304).end();
}
res.json(row.data);
});
**Spring (Java) sketch**java
@GetMapping("/resource/{id}")
public ResponseEntity<?> get(...) {
Row r = repo.findById(id);
String etag = "\""+r.getVersion()+"\"";
HttpHeaders h = new HttpHeaders();
h.setETag(etag);
h.setLastModified(r.getUpdatedAt().toEpochMilli());
if (request.checkNotModified(etag)) return new ResponseEntity<>(h, HttpStatus.NOT_MODIFIED);
return ResponseEntity.ok().headers(h).body(r.getData());
}
**Efficient ETag generation for large, frequently-changing resources**- Avoid full-content hashing on every request. Use: - Incrementing version column (Postgres bigserial or integer) updated in same transaction as content change — O(1) to read. - Last-updated timestamp (updated_at) for Last-Modified and weak ETag semantics. - Content-hash precompute on write only (trigger or app-level) stored in DB if you need strong ETags. - For composed resources, maintain a lightweight "aggregate_version" that changes when any part changes (materialized view or join-triggered update).- Trade-offs: - Version column: fastest, supports strong equality if updated deterministically. - Hash-on-write: accurate strong ETag, more storage but avoids read-time CPU. - Weak ETag (W/..): useful when byte-for-byte equality isn't required.**Validation rules & best practices**- Prefer If-None-Match over If-Modified-Since when both provided (RFC7232).- Ensure ETag and Last-Modified updated in same DB transaction to avoid races.- Use Cache-Control and Vary where appropriate.- Monitor hit-rate and tune max-age vs validation frequency.