Start · Sprachen · JavaScript · Referenz · Request.clone()

Request.clone()

Methode

Erstellt eine unabhängige Kopie eines <code>Request</code>-Objekts einschließlich Body, Headern und Optionen, sodass der Body mehrfach gelesen werden kann.

seit JavaScript Baseline: alle modernen Browser (seit 2017), Node. Kategorie: webapi

Signatur

Request.prototype.clone()

Beschreibung

Request.prototype.clone() gibt ein neues Request-Objekt zurück, das dieselben Eigenschaften wie das Original hat: URL, Methode, Header, Modus, Credentials, Cache-Einstellung, Redirect-Verhalten, Referrer, Integrity, signal und – ganz wichtig – den Body. Der Body wird dabei intern per Tee auf zwei Streams aufgeteilt, sodass Original und Kopie jeweils unabhängig voneinander gelesen werden können.

Man braucht die Methode immer dann, wenn der Body einer Anfrage mehr als einmal verwendet werden soll. Der Body eines Request ist ein ReadableStream und kann nur einmal konsumiert werden – durch fetch(), text(), json(), formData() usw. Danach ist bodyUsed gleich true. Typische Szenarien sind Wiederholungsversuche (Retry) nach einem Netzwerkfehler, das Protokollieren des Bodys vor dem Absenden oder Service Worker, die eine Anfrage sowohl weiterleiten als auch für eine Offline-Warteschlange speichern.

Die Kopie muss erstellt werden, bevor der Body gelesen wurde. Ist bodyUsed bereits true, wirft clone() einen TypeError.

Rückgabewert

Typ
Request
Beschreibung
Ein neues Request-Objekt, das eine exakte, unabhängige Kopie des ursprünglichen Requests ist (inklusive eines eigenen Body-Streams).

Beispiele

Body mehrfach lesen

const request = new Request('https://api.example.com/users', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ name: 'Anna' })
});

// Kopie VOR dem Lesen anlegen
const kopie = request.clone();

const text = await request.text();
console.log(text);
console.log(request.bodyUsed, kopie.bodyUsed);

// Die Kopie ist weiterhin lesbar
const daten = await kopie.json();
console.log(daten.name);
{"name":"Anna"} true false Anna

Retry-Logik mit fetch()

const fetchMitRetry = async (request, versuche = 3) => {
  for (let i = 1; i <= versuche; i++) {
    try {
      // Jeder Versuch bekommt eine frische Kopie, da fetch() den Body verbraucht
      const response = await fetch(request.clone());
      if (response.ok) return response;
      console.warn(`Versuch ${i}: Status ${response.status}`);
    } catch (err) {
      console.warn(`Versuch ${i} fehlgeschlagen:`, err.message);
    }
    await new Promise((r) => setTimeout(r, 500 * i));
  }
  throw new Error('Alle Versuche fehlgeschlagen');
};

const req = new Request('/api/bestellung', {
  method: 'POST',
  body: JSON.stringify({ artikel: 42, menge: 1 })
});

const res = await fetchMitRetry(req);
console.log(res.status);
200

Service Worker: Anfrage weiterleiten und für Offline-Queue sichern

self.addEventListener('fetch', (event) => {
  if (event.request.method !== 'POST') return;

  // Kopie für den Fehlerfall sichern, bevor fetch() den Body liest
  const sicherung = event.request.clone();

  event.respondWith(
    fetch(event.request).catch(async () => {
      const body = await sicherung.text();
      // z. B. in IndexedDB ablegen und später erneut senden
      console.log('Offline gespeichert:', sicherung.url, body);
      return new Response(JSON.stringify({ queued: true }), {
        status: 202,
        headers: { 'Content-Type': 'application/json' }
      });
    })
  );
});

Fehler: clone() nach dem Lesen

const req = new Request('/api', { method: 'POST', body: 'Hallo' });
await req.text();

try {
  req.clone();
} catch (err) {
  console.log(err.name);
}
TypeError

// Wichtig · Fallstricke

  • Zeitpunkt entscheidend: clone() wirft einen TypeError, wenn der Body bereits gelesen wurde (bodyUsed === true). Immer vor fetch() oder text()/json() klonen.
  • Speicher und Gegendruck: Durch das interne Tee des Streams werden Daten gepuffert, bis beide Zweige gelesen sind. Wird eine Kopie nie konsumiert, bleibt der gesamte Body im Speicher – bei großen Uploads problematisch. Nicht benötigte Kopien vermeiden oder deren Body mit body.cancel() verwerfen.
  • Zum Ändern nicht geeignet: clone() übernimmt alle Eigenschaften unverändert. Um z. B. Header oder URL anzupassen, stattdessen new Request(original, { headers: … }) verwenden.
  • Das signal wird übernommen: Ein Abbruch über den ursprünglichen AbortController betrifft auch die Kopie.
  • Requests ohne Body (z. B. GET) lassen sich jederzeit klonen.
  • Kompatibilität: In allen modernen Browsern, in Web Workern und Service Workern verfügbar; in Node.js ab Version 18 über das globale fetch/Request (undici).