← Recipes

阅读中文版本

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.

~30 minhttpcachingfrontend

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/config

Expected 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

  1. Store the ETag or Last-Modified value from the last successful response. Expected: The client remembers the validator per resource.
  2. Send it back as If-None-Match or If-Modified-Since on the next request. Expected: The server can answer 304 when unchanged.
  3. Treat 304 as reuse the stored body, not an error, and skip parsing. Expected: Unchanged responses cost a header round trip only.
  4. 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.