RFC 7233 - HTTP/1.1: 範囲リクエスト (Range Requests)
- ステータス: Proposed Standard
- 発行日: June 2014
- ストリーム: 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)
- 廃止されたドキュメント: RFC 2616
- ステータス: Standards Track (標準トラック)
概要
範囲リクエストにより、HTTPクライアントは完全な表現ではなく、リソースの1つ以上のサブ範囲を要求できます。これは、中断されたダウンロードの再開、マルチスレッドダウンロード、およびメディアストリーミング再生に不可欠です。
核心概念
範囲リクエストとは?
範囲リクエストにより、クライアントは次のように言うことができます: "このリソースの一部だけが必要です"。
完全なリソース: [================100MB================]
↓
範囲リクエスト: [====10MB====]
主な使用事例
- 中断されたダウンロードの再開: 中断後に続行
- セグメント化されたダウンロード: マルチスレッド並列ダウンロード
- ビデオスクラビング: ビデオの特定の位置にジャンプ
- 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
3つの連続していない範囲を要求します。
オープン範囲:
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
[3つのスレッドが並行してダウンロードし、その後マージ]
シナリオ4: PDF部分読み込み
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で範囲リクエストを再送信する必要があります。
まとめ
範囲リクエストはHTTP/1.1の重要な機能です:
- 正確性: バイト範囲セマンティクスの正確な実装
- 明確性: 部分コンテンツ要件の明確な表現
- 優雅さ: 最新のWebアプリケーションの高度な機能を優雅にサポート
範囲リクエストにより、大きなファイルの転送およびメディア再生時のユーザーエクスペリエンスを大幅に改善できます。
関連RFC:
- RFC 7230: HTTP/1.1 メッセージ構文とルーティング
- RFC 7231: HTTP/1.1 セマンティクスとコンテンツ
- RFC 7232: HTTP/1.1 条件付きリクエスト