【実務・中級編】Rangeヘッダーと206 Partial Contentの仕組み – HTTPプロトコル・通信規格実践ガイド

帯域を無駄にしない「賢い」通信:Rangeリクエストと206 Partial Contentの深淵

ネットワークエンジニアとして現場に立っていると、たまに「なぜかファイルが最後までダウンロードできない」「動画がシークするたびに最初から読み込まれる」といった相談を受ける。原因の多くは、HTTPの基本機能であるRangeリクエスト(バイトレンジ)の理解不足にある。

現代のWebにおいて、数ギガバイトのファイルを一気に転送するなんて野蛮なことはしない。今回は、HTTP/1.1の洗練された仕組みである「必要な場所だけを切り取る」技術、206 Partial Contentの裏側を紐解いていこう。

—

1. なぜ「全部」受け取る必要があるのか?

HTTP/1.1が登場する前、クライアントは「リソースの全体」しか要求できなかった。だが、想像してみてほしい。2時間の高画質動画を見ているとき、1分だけ飛ばしたいからといって、2時間分のデータをすべて破棄して再取得するのはあまりに非効率だ。

ここで登場するのが `Range` ヘッダーだ。クライアントはサーバーに対し、「ファイルの先頭からではなく、このバイト数からこのバイト数までをくれ」と指示できる。サーバーがその要求を正しく処理し、リクエストに応じた一部のデータだけを返せば、ステータスコードは `200 OK` ではなく、`206 Partial Content` に変わる。

Rangeヘッダーのキホン

クライアントが送るヘッダーの文法はシンプルだ。

ファイルの先頭500バイトを取得する場合
Range: bytes=0-499

500バイト目から最後までを取得する場合
Range: bytes=500-

最後の100バイトを取得する場合(サフィックス指定)
Range: bytes=-100

—

2. 現場で役立つ検証:curlでパケットの挙動を覗く

仕様書を読み込むのも良いが、まずは自分の手でパケットをキャプチャするのがエンジニアの流儀だ。`curl` を使って、サーバーが正しく部分レスポンスを返しているか確認しよう。

500バイト目から1000バイト目までを要求し、ヘッダーを表示する
curl -I -H “Range: bytes=500-1000” http://example.com/large-video.mp4

ここで注目すべきは、レスポンスヘッダーに含まれる以下のパラメータだ。

  • `Accept-Ranges: bytes`: 「うちはバイト単位のRangeリクエストをサポートしているよ」というサーバーの宣言。これがなければRangeリクエストは無視される。
  • `Content-Range: bytes 500-1000/5000000`: 「全5,000,000バイトのうち、500から1000バイト目を送るぞ」というサーバーからの回答。
  • `Content-Length: 501`: 返されるデータのサイズ。

—

3. 実装の現場:Fetch APIで「再開可能なダウンロード」を作る

フロントエンドやNode.js環境で、大容量ファイルのダウンロードを実装する際、`Range` を活用すれば通信が途切れても「途中から」再開できる。

async function downloadFilePart(url, start, end) {
const response = await fetch(url, {
headers: {
// 必要なバイト範囲を指定する
‘Range’: `bytes=${start}-${end}`
}
});

if (response.status !== 206) {
throw new Error(‘サーバーが部分リクエストをサポートしていません’);
}

return response.blob();
}

この実装があれば、ネットワークが瞬断しても、直前まで受信したバイト数を記録しておき、そこから再開するロジックを組むだけで済む。ユーザー体験(UX)を劇的に向上させる、インフラ屋が知っておくべきフロントエンドのTipsだ。

—

4. インフラ屋が気をつけるべき「罠」

Rangeリクエストを運用する際、必ず遭遇するのが「キャッシュ」の問題だ。

CDNやリバースプロキシ(Nginxなど)を挟んでいる場合、以下の点に注意しなければならない。

1. Varyヘッダーの指定:
キャッシュサーバーは「Rangeヘッダー付きのリクエスト」と「そうでないリクエスト」を別物として扱う必要がある。`Vary: Range` を適切に設定しておかないと、キャッシュの不整合(パージが必要な障害)に繋がる。
2. ETagの重要性:
Rangeリクエストでダウンロード中に、サーバー側のファイルが更新されてしまったらどうなるか?`ETag` を使って、「ダウンロード開始時と現在でファイルの中身が変わっていないか」を検証する仕組み(`If-Range`ヘッダーなど)を組み込むのが堅牢な設計だ。

Nginxでの設定例

もしあなたがNginxを管理しているなら、`max_ranges` 設定などで過剰なRangeリクエストによるDoS攻撃を防ぐことも忘れないでほしい。

1リクエストあたりの許容Range数を制限(デフォルトは無視されることが多いが明示する)
max_ranges 1;

キャッシュの整合性を保つための設定
proxy_set_header Range $http_range;
proxy_set_header If-Range $http_if_range;

—

最後に:プロトコルの美学

`206 Partial Content` は、単なる「一部を返す機能」ではない。限られた帯域を有効活用し、ユーザーの待ち時間を減らし、システムの堅牢性を高めるための、HTTPというプロトコルが持つ「知性」だ。

RFC 7233を一度読み通すことは、すべてのWebエンジニアにとって一生モノの投資になる。教科書を眺めるだけでなく、今日紹介した `curl` でのデバッグを、ぜひ君自身の環境で試してみてくれ。ネットワークの挙動が手に取るようにわかれば、障害対応のスピードは格段に上がるはずだ。

また次の現場で、技術的な深淵を覗こう。健闘を祈る。

コメント

タイトルとURLをコピーしました