A range request is the HTTP feature for asking for only part of a resource's bytes. Instead of re-downloading a whole large file from the start every time, you can say exactly 'give me only bytes 500 through 999 of this file.' That ability underpins many scenarios for handling big content efficiently — resuming an interrupted download, seeking in video, and parallel chunked downloads.
Accept-Ranges: advertising support
First you need to know whether the server supports ranges. The server advertises it with the Accept-Ranges: bytes response header, meaning 'I accept byte-range requests.' Conversely, Accept-Ranges: none or no header at all means ranges aren't supported, so the client must fetch the whole thing.
Range and 206 Partial Content
The client names the byte interval it wants in the Range request header. If the server can satisfy it, it responds not with 200 but 206 Partial Content, stating in the Content-Range header 'which slice of the total I'm sending.' The example below fetches bytes 0-1023 (the first 1KB) of a 20000-byte file.
GET /video.mp4 HTTP/1.1
Host: example.com
Range: bytes=0-1023
HTTP/1.1 206 Partial Content
Content-Range: bytes 0-1023/20000
Content-Length: 1024
Accept-Ranges: bytes
Content-Type: video/mp4
The Range syntax is flexible, letting you name an interval several ways.
bytes=0-1023: a specific interval, byte 0 through 1023.bytes=1024-: from byte 1024 to the end of the file.bytes=-500: the last 500 bytes of the file.bytes=0-99,200-299: several disjoint intervals at once (a multipart response).
416: when the range can't be satisfied
If the requested range falls outside the resource size (e.g. bytes=50000-60000 on a 20000-byte file), the server rejects with 416 Range Not Satisfiable. It should then report the real total size via Content-Range: bytes */20000, helping the client re-request a valid range.
Resuming and If-Range
A signature use of ranges is the resumable download. If a 100MB file dropped after 60MB, the client requests just the rest with Range: bytes=60000000-, avoiding a wasteful restart. But there's a trap — if the server's file changed mid-resume, stitching the old file's 60MB onto the new file's tail yields a corrupt file. The If-Range header prevents this. The client sends the ETag (or Last-Modified) from its initial fetch in If-Range; the server returns 206 with the remainder only if the file is unchanged, and otherwise sends 200 with the whole fresh file, safely restarting from scratch.
GET /big.zip HTTP/1.1
Host: example.com
Range: bytes=60000000-
If-Range: "a1b2c3"
HTTP/1.1 206 Partial Content
Content-Range: bytes 60000000-104857599/104857600
multipart/byteranges and video streaming
Request several intervals at once (Range: bytes=0-99,500-599) and the server returns them joined by a boundary string in a Content-Type: multipart/byteranges response, each part carrying its own Content-Range. Meanwhile, the video streaming we use daily is the most familiar application of ranges. When a video element starts playback, the browser first range-fetches the metadata at the file's head, and when the user drags the timeline forward (seeks), it requests exactly the byte interval at that point via Range. So jumping to the 1h30m mark of a 2GB movie needs no download of everything before it. Resumption, parallel downloads, and media seeking — much of the modern web's handling of large content rests on this small Range header.