VBScriptで挑む「大容量通信の再構築」:Rangeヘッダーによるダウンロード中断・再開の極意
レガシーシステムの墓場と揶揄されることもあるVBScript。しかし、Windows環境において、これほどまでに「OSの深層部」へ軽量にアクセスできる武器は他にない。
今日語るのは、ネットワークが不安定な環境下で、数GBに及ぶファイルを `MSXML2.ServerXMLHTTP` でいかに「死なせずに」ダウンロードしきるか、という極めて実戦的な技術だ。愚直に `ResponseStream` をメモリにぶち込むような素人仕事はここでは通用しない。
1. なぜ「Rangeヘッダー」が必要なのか
`ServerXMLHTTP` は便利だが、デフォルトでは「全ファイル取得」を試みる。ネットワークが一瞬でも瞬断すれば、それまで積み上げたメモリ上のバッファは霧散し、例外(Err)を吐いて終了する。
ここで我々が介入すべきは、HTTPプロトコルの `Range` ヘッダーだ。
「どこまで取得済みか」をファイルサイズから算出し、`bytes=開始位置-` という形式で要求することで、サーバーから差分だけを吸い出す。これが安定したデータ転送の要諦である。
2. 実装の設計思想:ADODB.Streamの使い所
VBScriptで大容量を扱う際、最大の敵は「メモリの浪費」と「オブジェクトの肥大化」だ。
データをメモリ上に保持してはいけない。`ADODB.Stream` をバイナリモードで開き、ディスクへ直接書き込み続ける。これが、数GBのファイルを扱ってもプロセスが落ちないための唯一の解法である。
3. 実践コード:Range指定によるダウンロード再開ロジック
以下に、中断を考慮した堅牢なダウンロード関数の骨子を示す。
‘ — 伝説のアーキテクトによる、堅牢なダウンロード制御ロジック —
Function DownloadFileResumable(strUrl, strFilePath)
Dim objXmlHttp, objStream, lngExistingSize
‘ 既存ファイルのサイズを取得(再開ポイントの特定)
lngExistingSize = GetFileSize(strFilePath)
Set objXmlHttp = CreateObject(“MSXML2.ServerXMLHTTP”)
Set objStream = CreateObject(“ADODB.Stream”)
‘ 既存ファイルがある場合は追記モード、なければ新規作成
objStream.Type = 1 ‘ adTypeBinary
objStream.Open
If lngExistingSize > 0 Then
objStream.LoadFromFile strFilePath
End If
objStream.Position = objStream.Size ‘ ポインタを末尾へ
‘ HTTPリクエストの構築
objXmlHttp.Open “GET”, strUrl, False
‘ Rangeヘッダーで「続き」を要求
If lngExistingSize > 0 Then
objXmlHttp.setRequestHeader “Range”, “bytes=” & lngExistingSize & “-”
End If
objXmlHttp.Send
‘ ステータスコードの確認(206 Partial Content が返れば成功)
If objXmlHttp.Status = 200 Or objXmlHttp.Status = 206 Then
objStream.Write objXmlHttp.responseBody
objStream.SaveToFile strFilePath, 2 ‘ adSaveCreateOverWrite
End If
‘ オブジェクトの完全解放(メモリリークを許さない)
objStream.Close
Set objStream = Nothing
Set objXmlHttp = Nothing
End Function
‘ 既存ファイルサイズ取得のヘルパー
Function GetFileSize(path)
Dim fso: Set fso = CreateObject(“Scripting.FileSystemObject”)
If fso.FileExists(path) Then
GetFileSize = fso.GetFile(path).Size
Else
GetFileSize = 0
End If
Set fso = Nothing
End Function
4. シニアエンジニアが意識すべき「闇」
このコードを実装する上で、以下の3点を忘れてはならない。
1. プロキシとキャッシュの罠: `MSXML2.ServerXMLHTTP` はプロキシ設定を OS のインターネットオプションから継承する。企業内NWで「なぜか古いファイルが落ちてくる」場合、キャッシュを無効化する `If-Modified-Since` 等のヘッダー追加を検討せよ。
2. 型変換の限界: `ADODB.Stream` の `Write` メソッドは強力だが、VBScriptのメモリ管理の制約上、一度に数GBを流し込むと `Variant` 型の扱いでスタックオーバーフローが発生する可能性がある。巨大なファイルは、数MB単位のチャンクに分割して取得するループ構造にするのが「真のプロフェッショナル」の流儀である。
3. 明示的解放の徹底: `Set obj = Nothing` を書かないのは、戦場で銃の整備を怠るのと同じだ。VBScriptのガベージコレクションを信用してはならない。特にCOMオブジェクトの解放は、スコープを抜ける前に必ず手動で行うこと。
最後に:レガシーを使いこなすということ
新しい言語を使えば解決する問題もある。しかし、この制約だらけの VBScript という環境で、いかにして現代のネットワーク要件を満たすか。その試行錯誤の中にこそ、エンジニアの「真の知見」が宿る。
これが、我々が守り続けてきた「堅牢な自動化」の現在地だ。安定稼働させるためのこだわりは、コードの行数ではなく、見えないオブジェクトのライフサイクルをどこまで制御できるかにかかっている。
