【JS応用|豆知識】Fetch APIを使いこなす!Request.prototype.clone() でリクエストを「複製」する方法

導入

Web開発でFetch APIを使用する際、一度送信したRequestオブジェクトを再利用しようとして「TypeError: Failed to execute ‘fetch’ on ‘Window’: Request object has already been used」というエラーに遭遇したことはありませんか?これは、Requestオブジェクトのボディ(Body)が「一度しか読み取れない(消費される)」という仕様によるものです。この課題を解決し、同じリクエストを複数回送るために欠かせないのが Request.prototype.clone() です。

基礎知識

Fetch APIのRequestオブジェクトは、ネットワーク経由でデータを送信するために作られています。セキュリティとパフォーマンスの観点から、ボディの内容(JSONデータなど)は一度ストリームとして読み取られると「消費済み(used)」というフラグが立ち、二度目の読み取りができなくなります。
Request.prototype.clone() は、その名の通り既存のRequestオブジェクトを複製し、新しいインスタンスを作成します。複製されたオブジェクトは「消費済み」フラグがリセットされた状態で生成されるため、再度fetch関数に渡すことが可能になります。

実装/解決策

実装の手順は非常にシンプルです。オリジナルのRequestオブジェクトに対して .clone() メソッドを呼び出し、その戻り値を新しい変数に代入するだけです。
ただし、注意点として「複製元のリクエストをfetchした後に、複製したリクエストをfetchする」という順序で行う必要があります。一度消費されたリクエストを複製しても、中身が正しくコピーされない場合があるため、「fetchする直前にcloneする」のが鉄則です。

サンプルプログラム

以下のコードは、同じリクエストを二回送信する例です。

// 1. リクエストのベースを作成
const request = new Request('https://api.example.com/data', {
  method: 'POST',
  body: JSON.stringify({ key: 'value' }),
  headers: { 'Content-Type': 'application/json' }
});

// 2. 一回目のfetch用にリクエストを複製
const request1 = request.clone();
fetch(request1).then(response => console.log('1回目完了:', response.status));

// 3. 二回目のfetch用にリクエストを再度複製
// オリジナルのrequestをそのまま使うのではなく、必ずclone()します
const request2 = request.clone();
fetch(request2).then(response => console.log('2回目完了:', response.status));

応用・注意点

現場で役立つ補足として、Request.prototype.clone() は「ボディがストリームとして読み取られていない状態」でのみ安全に動作します。
もし、一度bodyを json() や text() で読み取ってしまった後に clone() を呼び出そうとすると、エラーが発生したり、中身が空のまま複製されたりする可能性があります。
また、巨大なファイルを扱うRequestを何度も複製するとメモリを消費するため、不要なクローンは作成しないよう注意しましょう。
基本的には「fetchの直前にクローンを作成する」というパターンを覚えておけば、多くのケースでスマートに実装できます。

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