RFC 7233 - HTTP/1.1: 范围请求 (Range Requests)
- 状态: Proposed Standard
- 发布日期: June 2014
- Stream: IETF
- 废止: RFC2616 (部分)
- 被废止: RFC9110
- 勘误: 无勘误
文档信息
- RFC 编号: 7233
- 标题: Hypertext Transfer Protocol (HTTP/1.1): Range Requests
- 中文标题: 超文本传输协议 (HTTP/1.1): 范围请求
- 发布日期: 2014 年 6 月
- 作者: R. Fielding (Adobe), Y. Lafon (W3C), J. Reschke (greenbytes)
- 状态: Standards Track
注意: 本文档材料已被 [RFC 9110] 吸收与取代; 此处保留用于历史与对照.
摘要 (Abstract)
范围请求允许 HTTP 客户端请求资源的一个或多个子范围, 而非完整表示. 这对恢复中断的下载、多线程下载以及媒体流式播放至关重要.
核心概念
什么是范围请求?
范围请求使客户端可以说: "我只需要这个资源的一部分".
完整资源: [================100MB================]
↓
范围请求: [====10MB====]
主要用例
- 恢复中断的下载: 中断后继续传输
- 分段下载: 多线程并行下载
- 视频拖动 (scrubbing): 跳转到视频的特定位置
- PDF 预览: 仅下载前几页
- 大文件优化: 按需加载内容
Range 头字段
基本语法
Range: bytes=<start>-<end>
示例
单范围:
GET /video.mp4 HTTP/1.1
Host: example.com
Range: bytes=0-1023
请求前 1024 字节.
多范围:
GET /document.pdf HTTP/1.1
Host: example.com
Range: bytes=0-499, 1000-1499, 5000-5999
请求三个不连续的范围.
开放范围:
Range: bytes=1000- # 从 1000 到末尾
Range: bytes=-500 # 最后 500 字节
Range: bytes=0- # 从开头到末尾 (等价于完整请求)
Accept-Ranges 头
服务器用此头指示是否支持范围请求.
支持范围请求:
HTTP/1.1 200 OK
Accept-Ranges: bytes
Content-Length: 10485760
不支持范围请求:
HTTP/1.1 200 OK
Accept-Ranges: none
Content-Length: 10485760
206 Partial Content 响应
成功的范围请求返回状态码 206.
单范围响应
GET /video.mp4 HTTP/1.1
Range: bytes=1000-1999
HTTP/1.1 206 Partial Content
Content-Range: bytes 1000-1999/10485760
Content-Length: 1000
Content-Type: video/mp4
[1000 字节的数据...]
Content-Range 头
格式:
Content-Range: bytes <start>-<end>/<total>
示例:
Content-Range: bytes 1000-1999/10485760
^^^^^ ^^^^^ ^^^^^^^^
起始 结束 总大小
多范围响应
使用 multipart/byteranges 媒体类型:
GET /file.txt HTTP/1.1
Range: bytes=0-50, 100-150
HTTP/1.1 206 Partial Content
Content-Type: multipart/byteranges; boundary=THIS_STRING_SEPARATES
--THIS_STRING_SEPARATES
Content-Type: text/plain
Content-Range: bytes 0-50/1270
[前 51 字节...]
--THIS_STRING_SEPARATES
Content-Type: text/plain
Content-Range: bytes 100-150/1270
[中间 51 字节...]
--THIS_STRING_SEPARATES--
416 Range Not Satisfiable
当请求的范围无效时返回.
GET /file.txt HTTP/1.1
Range: bytes=9999-10999
HTTP/1.1 416 Range Not Satisfiable
Content-Range: bytes */1234
Content-Length: 0
常见原因:
- 起始位置超过文件大小
- 起始位置大于结束位置
- 格式错误
If-Range 条件范围请求
将条件请求与范围请求组合, 以确认资源尚未更改.
GET /video.mp4 HTTP/1.1
Range: bytes=1000000-
If-Range: "etag-abc123"
资源未更改 (ETag 匹配):
HTTP/1.1 206 Partial Content
ETag: "etag-abc123"
Content-Range: bytes 1000000-10485759/10485760
资源已更改 (ETag 不匹配):
HTTP/1.1 200 OK
ETag: "etag-xyz789"
Content-Length: 10485760
[返回完整的新资源...]
实际应用场景
场景 1: 恢复中断的下载
首次下载 (中断):
→ GET /large-file.zip HTTP/1.1
← HTTP/1.1 200 OK
Content-Length: 104857600
ETag: "file-v1"
[在 50MB 处中断...]
继续下载:
→ GET /large-file.zip HTTP/1.1
Range: bytes=52428800-
If-Range: "file-v1"
← HTTP/1.1 206 Partial Content
Content-Range: bytes 52428800-104857599/104857600
[下载剩余 50MB...]
场景 2: 视频流式播放
用户点击进度条 (跳到 50%):
→ GET /movie.mp4 HTTP/1.1
Range: bytes=524288000-524877999
← HTTP/1.1 206 Partial Content
Content-Range: bytes 524288000-524877999/1048576000
Content-Type: video/mp4
[返回约 590KB 视频数据...]
场景 3: 多线程下载
线程 1: Range: bytes=0-34999999
线程 2: Range: bytes=35000000-69999999
线程 3: Range: bytes=70000000-104857599
[三个线程并行下载后合并]
场景 4: PDF 部分加载
仅加载目录与前 10 页:
→ GET /document.pdf HTTP/1.1
Range: bytes=0-102400
← HTTP/1.1 206 Partial Content
Content-Range: bytes 0-102400/10485760
[返回文件头与前 10 页...]
Content-Range 响应头详解
完整语法
Content-Range: <unit> <range-start>-<range-end>/<size>
Content-Range: <unit> <range-start>-<range-end>/*
Content-Range: <unit> */<size>
示例
已知总大小:
Content-Range: bytes 200-1000/5000
未知总大小:
Content-Range: bytes 200-1000/*
无法满足 (416 响应):
Content-Range: bytes */5000
范围请求最佳实践
服务器侧
-
声明支持:
Accept-Ranges: bytes -
提供 ETag 或 Last-Modified:
ETag: "abc123"
Last-Modified: Wed, 21 Oct 2015 07:28:00 GMT -
正确验证范围:
- 检查范围是否在有效区间内
- 拒绝无效范围 (返回 416)
-
优化大范围请求:
- 考虑限制每请求的范围数量
- 避免过小范围带来的过高开销
客户端侧
-
检查 Accept-Ranges:
if (response.headers.get('Accept-Ranges') === 'bytes') {
// 支持范围请求
} -
使用 If-Range 保证一致性:
Range: bytes=1000-
If-Range: "etag-value" -
处理不同响应:
- 200: 服务器忽略 Range, 返回完整资源
- 206: 成功的部分响应
- 416: 范围无效, 可能需要重新请求
-
合理分块:
不要过小: bytes=0-1, bytes=1-2, bytes=2-3 ✗
合理大小: bytes=0-1048575 (1MB) ✓
范围单位
HTTP/1.1 主要支持 bytes 单位, 但规范允许扩展:
Accept-Ranges: bytes, frames, segments
bytes 单位最常用且已标准化.
性能考虑
优点
- 节省带宽: 仅传输需要的部分
- 改善体验: 支持断点续传与快速跳转
- 并行下载: 提高下载速度
潜在问题
- 缓存更复杂: 部分响应的缓存更难处理
- 服务器开销: 需要支持随机访问
- 范围碎片化: 过多小范围请求会降低效率
优化建议
推荐范围大小:
- 视频流: 1-5MB
- 文件下载: 5-10MB
- 文档浏览: 100KB-1MB
安全考虑
拒绝服务攻击
恶意客户端可能发送大量小范围请求:
Range: bytes=0-0, 1-1, 2-2, 3-3, ... (数千个范围)
防御:
- 限制每请求的范围数量 (例如最多 5 个)
- 限制响应总大小
- 实施速率限制
信息泄露
范围请求可能被用于推断文件大小或结构:
Range: bytes=0-0
→ Content-Range: bytes 0-0/[文件大小]
对敏感文件, 考虑禁用范围请求或要求认证.
与其他 HTTP 功能的交互
与缓存的交互
范围请求增加缓存复杂度:
Vary: Range
Cache-Control: private
与压缩的交互
注意: 范围请求通常不与 Content-Encoding: gzip 一起使用, 因为压缩后的偏移不可预测.
建议: 需要范围请求的大文件不要使用传输压缩.
与重定向的交互
范围请求遇到重定向时:
GET /old-video.mp4 HTTP/1.1
Range: bytes=1000-1999
HTTP/1.1 302 Found
Location: /new-video.mp4
客户端必须在新 URL 上重新发送范围请求.
规范章节对照
| 章节 | 内容 |
|---|---|
| 1 | 引言, 一致性, 语法记法 |
| 2 | 范围单位, 字节范围, Accept-Ranges |
| 3 | Range 与 If-Range |
| 4 | 206, Content-Range, 多范围, 416 |
| 5 | IANA 考虑 |
| 6 | 安全考虑 |
| 附录 A | multipart/byteranges |
总结
范围请求是 HTTP/1.1 的重要功能:
- 准确性: 精确实现字节范围语义
- 清晰性: 明确表达部分内容需求
- 实用性: 优雅支持现代 Web 的高级功能
范围请求可显著改善大文件传输与媒体播放时的用户体验.
相关资源
- 官方文本: https://www.rfc-editor.org/rfc/rfc7233.txt
- DataTracker: https://datatracker.ietf.org/doc/html/rfc7233
- 后继: RFC 9110 (HTTP Semantics)
- 相关: RFC 7230, RFC 7231, RFC 7232
1. 引言 (规范结构)
HTTP 范围请求机制使客户端能够请求资源表示的一个或多个子范围. 本规范定义范围单位, 请求语义, 响应状态码与头字段, 以及安全与 IANA 考虑.
1.1 一致性与错误处理
关键词 "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY" 和 "OPTIONAL" 的解释见 BCP 14 [RFC2119] [RFC8174].
不符合本规范要求的实现可能与其他实现无法互操作. 接收方在面对畸形 Range 值时 SHOULD 忽略该头或返回适当错误.
1.2 语法记法
本规范使用 [RFC5234] ABNF, 以及 HTTP 列表扩展规则. bytes-unit 与 byte-range-set 等产生式定义字节范围语法.
2. 范围单位 (Range Units) 规范细节
2.1 字节范围 (Byte Ranges)
字节范围以从零开始的索引标识表示中的八位组. 客户端可请求:
- 闭区间:
bytes=0-499(前 500 字节) - 从某偏移到末尾:
bytes=500- - 后缀范围:
bytes=-500(最后 500 字节) - 多范围集合: 逗号分隔的多个范围
服务器在满足请求时 MUST 在 Content-Range 中准确反映实际返回的范围.
2.2 其他范围单位
除 bytes 外, 可注册其他范围单位. 不理解的单位 MUST 被忽略, 使得请求可退化为普通 GET (若服务器选择忽略整个 Range) 或导致错误处理. 互操作部署中, bytes 是事实上的基线.
2.3 Accept-Ranges
Accept-Ranges: bytes 表示服务器愿意接受字节范围请求. Accept-Ranges: none 明确拒绝. 省略该头并不禁止范围请求, 但客户端无法先验知道支持情况.
3. 范围请求语义
3.1 Range
Range 头字段修改 GET (及其他允许的方法, 若适用) 的含义, 请求部分表示. 若服务器不支持范围, 它可忽略 Range 并返回 200 与完整表示.
3.2 If-Range
If-Range 的值可以是实体标签 (ETag) 或 HTTP 日期. 仅当表示验证器匹配时, 服务器才返回 206 部分内容; 否则返回完整 200 响应. 这对断点续传在资源变更时避免拼接错误至关重要.
4. 响应细则
4.1 206 Partial Content
206 响应的有效载荷是一个或多个表示范围. 单范围时使用普通 Content-Type 与 Content-Range. 多范围时使用 multipart/byteranges.
4.2 Content-Range
接收方使用 Content-Range 确定部分内容在完整表示中的位置. 完整长度未知时使用 *.
4.3 组合范围
服务器 MAY 合并重叠或相邻范围. 客户端 MUST 能处理服务器返回的实际范围集合, 即使与请求不完全一致 (在合法合并情况下).
4.4 416 Range Not Satisfiable
当每个指定的字节范围的第一字节位置都大于当前表示长度时, 服务器 SHOULD 生成 416. 416 响应通常包含 Content-Range: bytes */<length> 以告知客户端当前长度.
5. IANA 考虑 (摘要)
本规范涉及:
- 范围单位注册表
- 状态码 206 与 416 的注册说明
- 头字段
Accept-Ranges,Range,Content-Range,If-Range - 媒体类型
multipart/byteranges
现行 HTTP 语义以 [RFC9110] 为准.
6. 安全考虑 (扩展)
6.1 使用范围的拒绝服务
攻击者可构造:
- 数千个单字节范围
- 高度重叠的范围集合
- 迫使服务器进行昂贵的随机 I/O 的请求
缓解措施包括限制范围个数, 限制总服务字节数, 以及对匿名客户端实施更严格配额.
6.2 缓存与共享缓存风险
部分响应的缓存键必须包含范围信息, 否则可能向客户端提供错误片段. 共享缓存实现 MUST 正确处理 Content-Range 与验证器.
7. 致谢与参考文献
本材料源自 RFC 7233 作者 Fielding, Lafon 与 Reschke 的工作. 完整规范性与资料性引用见英文源与 [RFC9110].
关键词保留: MUST, SHOULD, MAY, Range, Content-Range, Accept-Ranges, If-Range, 206, 416, multipart/byteranges.