A conditional GET: send back the ETag you received earlier via `If-None-Match`, and if the resource is unchanged you get just a 304 Not Modified, saving bandwidth.
A conditional GET: send back the ETag you received earlier via `If-None-Match`, and if the resource is unchanged you get just a 304 Not Modified, saving bandwidth.
# 1) first request returns an ETag
curl -i https://api.example.com/config
# ETag: "a1b2c3"
# 2) revalidate: send it back, get 304 if unchanged
curl -i https://api.example.com/config \
-H 'If-None-Match: "a1b2c3"'const first = await fetch('/config');
const etag = first.headers.get('ETag');
const next = await fetch('/config', {
headers: { 'If-None-Match': etag }
});
if (next.status === 304) {
// not modified — reuse cached body
}import requests
r1 = requests.get('https://api.example.com/config')
etag = r1.headers['ETag']
r2 = requests.get('https://api.example.com/config',
headers={'If-None-Match': etag})
print(r2.status_code) # 304 if unchanged (r2.content is empty)Store the first response's `ETag` (a resource-version identifier), then send it on the next request as `If-None-Match: "<etag>"`. If nothing changed, the server returns 304 with no body and you reuse your cached copy; if it changed, you get 200 with a fresh body and a new ETag.
ETags come in strong form (`"..."`) and weak form (`W/"..."`). A weak ETag treats semantically-equivalent representations as equal, which makes it unsuitable for byte-exact operations like Range requests.
The time-based alternative is `Last-Modified` + `If-Modified-Since`, but it only has one-second resolution. On writes (PUT/DELETE), conditional requests use `If-Match` for optimistic locking, and a mismatch yields 412 Precondition Failed.