【実務・中級編】HTTP/1.1のRangeヘッダーによる部分リクエストの仕様 – HTTPプロトコル・通信規格実践ガイド

ネットワークの「分断」を制する:HTTP/1.1 Rangeヘッダーによる賢いデータ転送術

ネットワークエンジニアとして現場に立っていると、大容量ファイルを扱う際の「転送中断」ほど忌々しいトラブルはありません。3GBのログファイルや動画データをダウンロードしている最中に、残り1%で接続が切れる……。これを全損として最初からやり直すのは、帯域の無駄であり、ユーザー体験を損なう最大の悪手です。

HTTP/1.1が導入した「Rangeヘッダー」は、まさにこの絶望から我々を救うための魔法の杖です。今回は、単なる仕様の解説を超え、エンジニアが実務で必ず直面する「部分リクエスト」の深淵に迫りましょう。

—

1. Rangeヘッダーのメカニズム:断片をつなぎ合わせる技術

Rangeヘッダーは、クライアントが「ファイル全体ではなく、この範囲のバイト列だけをくれ」とサーバーに要求するための仕組みです。

通信の基本フローは非常にシンプルですが、理解しておくべきはステータスコード `206 Partial Content` の存在です。

通信シーケンスのリアル

1. クライアント: `Range: bytes=0-1023` を付けてリクエスト。
2. サーバー: ファイルの先頭1024バイトを読み出し、`HTTP/1.1 206 Partial Content` を返す。
3. ヘッダー: `Content-Range` ヘッダーにて「今送っているのが全体の中のどこか」を明示する。

このやり取りにより、ネットワークの不安定さを「再開可能なプロセス」へと昇華させることができるのです。

—

2. 現場で役立つRange指定のパターン

Rangeの指定方法はRFC 7233で定義されていますが、実務で使うのは主に以下の3パターンです。

  • `bytes=0-499`: 先頭から500バイト(0〜499)を取得。
  • `bytes=500-`: 500バイト目から「末尾まで全て」を取得。
  • `bytes=-500`: ファイルの「最後の500バイト」を取得(ログの末尾確認などで重宝します)。

注意すべきポイント:Content-Rangeの読み方

サーバーが返すレスポンスには、必ず `Content-Range: bytes –/` が含まれます。
例えば `Content-Range: bytes 0-1023/5000` とあれば、「5000バイトのファイルのうち、0〜1023バイトを送ったよ」という意味です。この `/5000`(総サイズ)を確認せずに実装を進めると、後で泣きを見ることになります。

—

3. 実践:デバッグと実装の現場から

理論だけでは現場は回せません。デバッグや実装で即座に使えるツール別のTipsを紹介します。

curlで疎通確認を行う

まずは、バックエンドAPIがRangeに対応しているかをサクッと確認しましょう。

最初の1KBだけを抜き取ってヘッダーを確認する
curl -I -H “Range: bytes=0-1023” http://example.com/large-file.mp4

もし「Accept-Ranges: bytes」がレスポンスに含まれていれば、そのサーバーはRange対応です。

Pythonで「レジューム可能」なダウンローダーを作る

単純な `requests.get` ではなく、Rangeを使ってレジューム機能を実装する際の骨組みです。

import requests

def download_file(url, local_filename):
# すでにファイルが存在すれば、そのサイズを起点にリクエスト
file_size = os.path.getsize(local_filename) if os.path.exists(local_filename) else 0

headers = {‘Range’: f’bytes={file_size}-‘}

with requests.get(url, headers=headers, stream=True) as r:
# 206が返ってくることを期待する
if r.status_code == 206:
with open(local_filename, ‘ab’) as f: # 追記モード(‘ab’)で保存
for chunk in r.iter_content(chunk_size=8192):
f.write(chunk)
else:
# 200が返ってきたら、サーバーがRange非対応なので上書き開始
with open(local_filename, ‘wb’) as f:
f.write(r.content)

—

4. インフラ屋の視点:Nginxでの挙動

Webサーバー側(Nginxなど)では、Rangeリクエストは基本的にデフォルトで有効ですが、キャッシュサーバー(CDNやVarnish)を挟む場合は注意が必要です。

もしNginxの設定で「Rangeのリクエストを処理させたくない」あるいは「キャッシュを最適化したい」場合は、以下のように確認してください。

nginx.conf の設定例
max_ranges が 0 だとRangeリクエストを無視します
max_ranges 1;

キャッシュの際、Rangeリクエストを個別のキャッシュキーにしないと
誤ったデータが返る(キャッシュ汚染)リスクがあるため、
プロキシ側の設定には細心の注意を払ってください。

—

最後に:ネットワークを「信頼」するな

Rangeヘッダーは便利な機能ですが、忘れてはならないのは「ネットワークは本来、断絶するもの」という大前提です。

Rangeを適切に扱うことは、単に帯域を節約することではありません。サーバーとクライアントの間にある不安定な物理層や論理層を、プロトコルレベルで「継続可能な関係」に再構築することです。

もし運用中に「Range指定したのに200 OKが返ってくる」「Content-Rangeが期待した範囲と違う」といった現象に遭遇したら、まずは途中のCDNやプロキシがリクエストを改ざんしていないか疑ってください。パケットは嘘をつきません。`tcpdump` で生のヘッダーを叩き、その目で真実を確認する。それこそが、一流のネットワークエンジニアへの近道です。

さあ、皆さんのコードにも、この「中断に負けない堅牢性」を実装してみてください。質問があれば、いつでも現場の知見を共有します。

コメント

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