Files
llm-wiki/raw/official-docs/mdn-http-range-fetch-transfer.md
T

104 lines
9.8 KiB
Markdown

---
title: MDN — HTTP Range requests / Fetch 취소·스트림 소비
source_type: official-doc
url: https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/Range_requests
archive_url:
related_branches: [feature-frontend-large-object-transfer-contract]
related_projects: [ca-skeleton-frontend]
tags: [frontend, http, range, fetch, streaming, transfer]
created: 2026-07-28
---
# MDN — HTTP Range requests / Fetch 취소·스트림 소비
> Layer: `raw/` — 외부 자료의 **원문 발췌·출처 기록**.
## 활용 branch (필수, 최소 1개+)
| Branch | 이 자료가 정당화하는 결정 |
|---|---|
| `[[raw/branch-notes/feature-frontend-large-object-transfer-contract]]` | `StreamingDownloadPort` 의 재개 프로토콜(`D4`), part 재시도가 stream 재사용이 아니라 재slice 여야 하는 이유(`D6`), 취소의 error 매핑(`D7`) |
## 출처
- 원본 URL: https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/Range_requests
- 보조 URL: https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch
- 아카이브 URL:
- 저자 / 조직: MDN Web Docs (Mozilla)
- 발행일: (문서 지속 갱신)
- 마지막 확인일: 2026-07-28
## 왜 저장했는지
branch 의 `resumeStrategy: range` 와 "part 재시도 상한 2회" 가 **어떤 프로토콜 사실 위에 서 있는지** 확인하지 않은 상태였다. 특히 세 가지가 필요했다. (a) 재개가 서버 지원에 의존한다면 미지원을 어떻게 감지하는가, (b) 재개 중 원본이 바뀌면 무엇이 깨지는가, (c) 실패한 part 를 재시도할 때 이미 소비한 body 를 다시 쓸 수 있는가. (c) 는 재시도 구현이 조용히 빈 body 를 보내는 고전적 버그의 원인이다.
## 핵심 인용
> [§Checking if a server supports partial requests] "If an HTTP response includes the `Accept-Ranges` header with any value other than `none`, the server supports range requests."
> [§Checking if a server supports partial requests] "If responses omit the `Accept-Ranges` header, it indicates the server doesn't support partial requests."
> [§Requesting a specific range from a server] "If the server supports range requests, you can specify which part (or parts) of the document you want the server to return by including the `Range` header in a HTTP request."
> [§Single part ranges] "The `Content-Range` response header indicates where this partial message belongs within the full resource."
> [§Partial request responses] "A range request that is out of bounds will result in a `416` `Requested Range Not Satisfiable` status, meaning that none of the range values overlap the extent of the resource."
> [§Partial request responses] "If range requests are not supported, an `200` `OK` status is sent back and the entire response body is transmitted."
> [§Conditional range requests] "When resuming to request more parts of a resource, you need to guarantee that the stored resource has not been modified since the last fragment has been received."
> [§Conditional range requests] "The `If-Range` HTTP request header makes a range request conditional: if the condition is fulfilled, the range request will be issued and the server sends back a `206` `Partial Content` answer with the appropriate body. If the condition is not fulfilled, the full resource is sent back, with a `200` `OK` status."
> [§Using Fetch — Canceling a request] "To make a request cancelable, create an `AbortController`, and assign its `AbortSignal` to the request's `signal` property."
> [§Using Fetch — Canceling a request] "To cancel the request, call the controller's `abort()` method. The `fetch()` call will reject the promise with an `AbortError` exception."
> [§Using Fetch — Canceling a request] "If the request is aborted after the `fetch()` call has been fulfilled but before the response body has been read, then attempting to read the response body will reject with an `AbortError` exception."
> [§Using Fetch — Streaming the response body] "Request and response bodies are actually `ReadableStream` objects, and whenever you read them, you're streaming the content."
> [§Using Fetch — Locked and disturbed streams] "This means it's not possible to read the same response (or request) body more than once"
> [§Using Fetch — Locked and disturbed streams] "if any content has been read from the stream, then the stream is _disturbed_, and nothing else can read from the stream."
## 추출된 주장
| Claim ID | Claim (이 자료가 직접 말하는 것) | Evidence quote | Strength | Applies to | Does not prove |
|---|---|---|---|---|---|
| C1 | 서버의 range 지원 여부는 `Accept-Ranges` 헤더로 판별하며 `none` 또는 헤더 부재는 미지원을 뜻한다 | [§Checking] "with any value other than `none`, the server supports range requests" / "If responses omit the `Accept-Ranges` header, it indicates the server doesn't support partial requests." | `official-reference` | 모든 HTTP 응답 | 특정 스토리지 vendor 가 이 헤더를 보내는지 |
| C2 | 부분 응답의 위치는 `Content-Range` 가 알려주며 상태 코드는 `206` 이다 | [§Single part ranges] "The `Content-Range` response header indicates where this partial message belongs within the full resource." | `official-reference` | `206` 응답 | 클라이언트가 요청한 범위와 서버가 준 범위가 항상 같다는 것 |
| C3 | 범위가 리소스 밖이면 `416 Requested Range Not Satisfiable` 이 온다 | [§Partial request responses] "will result in a `416` `Requested Range Not Satisfiable` status" | `official-reference` | 잘못된 재개 위치 | 416 이 재시도로 회복 가능한지 |
| C4 | range 를 지원하지 않으면 `200 OK` 와 **전체 본문**이 온다 — 조용히 성공한 것처럼 보인다 | [§Partial request responses] "an `200` `OK` status is sent back and the entire response body is transmitted." | `official-reference` | 재개 시도 | 200 응답을 받은 클라이언트가 자동으로 이를 알아챈다는 것 — 상태 코드를 검사해야만 안다 |
| C5 | 재개 시에는 마지막 조각 수신 이후 원본이 변경되지 않았음을 **보장해야 한다** | [§Conditional range requests] "you need to guarantee that the stored resource has not been modified since the last fragment has been received." | `official-reference` | 모든 이어받기 | 어떤 validator(ETag vs Last-Modified)를 써야 하는지 |
| C6 | `If-Range` 는 조건 충족 시 `206`, 불충족 시 `200` 과 전체 리소스를 돌려준다 | [§Conditional range requests] "If the condition is not fulfilled, the full resource is sent back, with a `200` `OK` status." | `official-reference` | 조건부 재개 | 불충족을 오류로 취급해야 하는지 — 프로토콜상 정상 응답이다 |
| C7 | `AbortController``signal` 로 요청을 취소하며 `fetch()``AbortError` 로 reject 된다 | [§Canceling a request] "The `fetch()` call will reject the promise with an `AbortError` exception." | `official-reference` | 모든 fetch 요청 | 이미 전송된 바이트가 서버에서 취소된다는 것 |
| C8 | 응답 수신 후 body 읽기 전에 취소하면 **body 읽기가** `AbortError` 로 reject 된다 | [§Canceling a request] "attempting to read the response body will reject with an `AbortError` exception." | `official-reference` | 취소 타이밍이 늦은 경우 | 두 경로의 error 를 구분해야 하는지 |
| C9 | request·response body 는 `ReadableStream` 이며 읽는 순간 스트리밍된다 | [§Streaming the response body] "Request and response bodies are actually `ReadableStream` objects" | `official-reference` | fetch body | 요청 body 로 스트림을 넘길 때의 추가 요구사항(`duplex` 등) — 이 페이지는 다루지 않음 |
| C10 | 같은 body 를 **두 번 읽을 수 없다**. 한 번 읽힌 스트림은 disturbed 상태가 되어 누구도 다시 읽지 못한다 | [§Locked and disturbed streams] "it's not possible to read the same response (or request) body more than once" / "the stream is _disturbed_, and nothing else can read from the stream." | `official-reference` | 모든 fetch body | 재시도가 불가능하다는 뜻은 아님 — **새 body 를 만들면** 가능하다 |
## 적용 경계
- 이 자료가 직접 증명하는 것:
- `C1`~`C6`: 이어받기의 지원 판별·위치 표현·실패 코드·조건부 재개
- `C7`·`C8`: 취소의 오류 표면
- `C9`·`C10`: body 스트림의 1회 소비 제약
- 이 자료가 증명하지 않는 것:
- **업로드** 스트리밍(요청 body 를 `ReadableStream` 으로 주는 경우)의 요구사항 — `duplex` 옵션과 HTTP/2 요구를 이 페이지는 언급하지 않는다
- part 재시도 횟수의 적정값 — 프로토콜은 횟수를 말하지 않는다
- 어떤 validator(`ETag`/`Last-Modified`)를 `If-Range` 에 써야 하는지
- 내 프로젝트에 적용하려면 추가 확인이 필요한 것:
- 선택할 object storage 가 `Accept-Ranges``If-Range` 를 실제로 지원하는지(`FE-Q-012`)
- 스트리밍 업로드가 필요한지, 필요하다면 `duplex` 지원 매트릭스
## 메모
- 인용 1 해석 후보 (미검증): `C4` 는 조용한 실패의 원천이다. 이어받기를 요청했는데 `200` 이 오면 클라이언트는 **처음부터 다시 받고 있는 중**인데도 "재개 성공" 으로 착각하기 쉽다. adapter 는 `206` 을 명시적으로 확인해야 한다.
- 인용 2 해석 후보 (미검증): `C10` 때문에 part 재시도는 **원본 `Blob` 을 다시 slice** 해야 한다. 첫 시도에서 만든 body 를 보관했다가 재사용하면 disturbed 스트림을 보내게 된다.
- 추가로 봐야 할 동일 출처 페이지: `Request.duplex`, `If-Range`, `Accept-Ranges`, `AbortSignal.timeout()`
## 관련
- 같은 주제 다른 official-doc: `[[raw/official-docs/aws-s3-multipart-upload-limits]]`, `[[raw/official-docs/mdn-referrer-policy]]`
- 이 자료를 인용한 wiki 요약: 생성 전