범위 요청(Range Requests)

Range·Content-Range·Accept-Ranges 헤더, 206과 416, 이어받기(resumable) 다운로드, If-Range, multipart/byteranges, 그리고 동영상 스트리밍에서의 활용을 설명합니다.

범위 요청은 리소스의 일부 바이트만 요청하는 HTTP 기능입니다. 큰 파일 전체를 매번 처음부터 받는 대신, '이 파일의 500번째부터 999번째 바이트만 달라'고 정확히 지정할 수 있죠. 이 능력은 끊긴 다운로드 이어받기, 동영상 탐색(seek), 병렬 분할 다운로드처럼 대용량 콘텐츠를 효율적으로 다루는 여러 시나리오의 기반이 됩니다.

Accept-Ranges: 지원 여부 알리기

먼저 서버가 범위 요청을 지원하는지 알아야 합니다. 서버는 응답에 Accept-Ranges: bytes 헤더를 실어 '바이트 단위 범위 요청을 받는다'고 광고합니다. 반대로 Accept-Ranges: none이거나 헤더가 아예 없으면 범위를 지원하지 않는다는 뜻이므로, 클라이언트는 전체를 받아야 합니다.

Range와 206 Partial Content

클라이언트는 Range 요청 헤더로 원하는 바이트 구간을 지정합니다. 서버가 이를 만족하면 200이 아니라 206 Partial Content로 응답하고, Content-Range 헤더에 '전체 크기 중 어느 구간을 보내는지'를 명시합니다. 아래 예는 총 20000바이트짜리 파일에서 0~1023바이트(첫 1KB)를 받는 모습입니다.

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

Range 문법은 유연해서 다양한 방식으로 구간을 지정할 수 있습니다.

416: 범위를 만족할 수 없을 때

요청한 범위가 리소스 크기를 벗어나면(예: 20000바이트 파일에 bytes=50000-60000 요청) 서버는 416 Range Not Satisfiable로 거절합니다. 이때 서버는 Content-Range: bytes */20000처럼 실제 전체 크기를 알려주어, 클라이언트가 올바른 범위로 다시 요청하도록 돕는 것이 좋습니다.

이어받기와 If-Range

범위 요청의 대표적 실전 용도가 이어받기(resumable download)입니다. 100MB 파일을 60MB 받다가 연결이 끊겼다면, 클라이언트는 Range: bytes=60000000-으로 나머지만 요청해 처음부터 다시 받는 낭비를 피합니다. 그런데 여기엔 함정이 있습니다 — 이어받는 동안 서버의 파일이 바뀌었다면, 옛 파일의 60MB와 새 파일의 나머지를 이어 붙여 손상된 파일이 됩니다. 이를 막는 것이 If-Range 헤더입니다. 클라이언트가 처음 받을 때의 ETag(또는 Last-Modified)를 If-Range에 실어 보내면, 서버는 파일이 그대로일 때만 206으로 나머지를 주고, 바뀌었으면 206 대신 200으로 전체를 새로 내려보내 안전하게 처음부터 받게 합니다.

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와 동영상 스트리밍

여러 구간을 한 번에 요청하면(Range: bytes=0-99,500-599) 서버는 각 구간을 경계 문자열로 구분해 이어 붙인 Content-Type: multipart/byteranges 응답으로 돌려줍니다. 각 파트마다 자신의 Content-Range가 붙습니다. 한편 우리가 매일 쓰는 동영상 스트리밍이야말로 범위 요청의 가장 익숙한 응용입니다. 동영상 태그가 재생을 시작하면 브라우저는 파일 앞부분의 메타데이터를 먼저 범위로 받고, 사용자가 타임라인을 앞으로 끌면(seek) 그 지점에 해당하는 바이트 구간을 Range로 콕 집어 요청합니다. 덕분에 2GB 영화의 1시간 30분 지점으로 순간 이동해도 앞부분을 전부 받을 필요가 없습니다. 이어받기·병렬 다운로드·미디어 seek — 대용량을 다루는 현대 웹의 상당 부분이 이 작은 Range 헤더 위에 서 있습니다.