What is the If-Range header?
The If-Range request header, defined in RFC 9110 Section 13.1.5, makes a Range request conditional. Its meaning is: if the representation still matches this validator, send me the ranges I asked for; otherwise ignore the Range header and send me the entire current representation. The value is either an entity tag or an HTTP-date.
API Usage & Best Practices
- Resume downloads safely: When a client resumes an interrupted download, it sends the
ETagit received with the first part. If the resource is unchanged, the server returns206 Partial Contentwith the missing bytes. If it has changed, the server returns200 OKwith the full new body, so the client never stitches together bytes from two different versions. - One round trip instead of two: Using
If-MatchorIf-Unmodified-SincewithRangewould get a412 Precondition Failedon a change and force a second request.If-Rangeis the only conditional that falls back to the full representation instead of failing. - Strong validators only: A client must not send a weak entity tag (
W/"...") inIf-Range, and the server compares entity tags with the strong comparison function. Send a date only when you have no entity tag and the date is a strong validator in the sense of RFC 9110 Section 8.8.2.2. Date comparison is an exact match againstLast-Modified, not the “earlier than or equal to” rule used byIf-Unmodified-Since. - Only meaningful with Range: A client must not send
If-RangewithoutRange, and a server must ignore it in that case, or when the resource does not support range requests (advertise support withAccept-Ranges). - Server side: If your API serves large exports or files, emit strong ETags on them. Without a strong validator, clients cannot resume reliably and fall back to re-downloading everything.
Examples
The client already holds the first 1 MiB of an export and asks for the rest, but only if it is the same export:
GET /v1/exports/exp_9f2/download HTTP/1.1Host: api.example.comRange: bytes=1048576-If-Range: "a7c3e9b2"Unchanged, so the server sends the remaining bytes:
HTTP/1.1 206 Partial ContentETag: "a7c3e9b2"Content-Range: bytes 1048576-4194303/4194304Content-Length: 3145728Had the export been regenerated, the server would ignore Range and answer 200 OK with the full new file and its new ETag.