Use Conditional Requests to Save Bandwidth
Store the ETag or Last-Modified value, send it back with If-None-Match, and handle the 304 so unchanged resources cost almost nothing.
Task
Make a polling client revalidate with conditional headers instead of downloading unchanged payloads.
When to use this
A client polls an API every few seconds and downloads the full body every time even when nothing changed, wasting bandwidth and battery.
Prerequisites
- A server that returns ETag or Last-Modified
- A client-side store for the validator
Steps
1. Store the ETag or Last-Modified value from the last successful response.
Expected output: The client remembers the validator per resource.
2. Send it back as If-None-Match or If-Modified-Since on the next request.
Expected output: The server can answer 304 when unchanged.
3. Treat 304 as reuse the stored body, not an error, and skip parsing.
Expected output: Unchanged responses cost a header round trip only.
4. Fall back to a full fetch when no validator is stored.
curl -i -H 'If-None-Match: "abc123"' https://api.example.com/configExpected output: First and cache-miss requests still work.
Troubleshooting
Problem
Client sends a stale validator
Solution
Replace the stored validator only on 200 responses, never on 304.
Problem
Proxy strips the ETag
Solution
Verify the header survives the CDN; a stripped validator forces full downloads.
Limitations
- Conditional requests still require a round trip and server-side comparison, so they reduce bytes, not latency.
- They do not help if the resource changes on every request.
Context
Make a polling client revalidate with conditional headers instead of downloading unchanged payloads. A client polls an API every few seconds and downloads the full body every time even when nothing changed, wasting bandwidth and battery.
Steps
- Store the ETag or Last-Modified value from the last successful response. Expected: The client remembers the validator per resource.
- Send it back as If-None-Match or If-Modified-Since on the next request. Expected: The server can answer 304 when unchanged.
- Treat 304 as reuse the stored body, not an error, and skip parsing. Expected: Unchanged responses cost a header round trip only.
- Fall back to a full fetch when no validator is stored. Expected: First and cache-miss requests still work.
const res = await fetch(url, {
headers: store.etag ? { 'If-None-Match': store.etag } : {},
});
if (res.status === 304) return store.body;
store.etag = res.headers.get('etag');
store.body = await res.json();
return store.body;
Verify
- The client remembers the validator per resource.
- The server can answer 304 when unchanged.
- Unchanged responses cost a header round trip only.
- First and cache-miss requests still work.
Limits
- Conditional requests still require a round trip and server-side comparison, so they reduce bytes, not latency.
- They do not help if the resource changes on every request.