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

Request.textStream()

Methode

Gibt einen <code>ReadableStream</code> zurück, der den Request-Body stückweise als UTF-8-dekodierte Zeichenketten liefert.

seit JavaScript Experimentell: noch nicht Baseline, nur in einzeln Kategorie: webapi

Signatur

Request.prototype.textStream()

Beschreibung

Die Methode textStream() der Schnittstelle Request liefert den Body einer Anfrage als ReadableStream aus Zeichenketten statt aus rohen Bytes (Uint8Array). Die UTF-8-Dekodierung übernimmt der Browser. Auch Multibyte-Zeichen, die über Chunk-Grenzen hinweg aufgeteilt sind, werden dabei korrekt zusammengesetzt.

Im Ergebnis entspricht das dem bisher üblichen Muster request.body.pipeThrough(new TextDecoderStream()), nur kürzer. Anders als Request.text() wartet die Methode nicht, bis der ganze Body gelesen ist. Du kannst also schon mit der Verarbeitung beginnen, während noch Daten ankommen. Das spart Speicher und lohnt sich besonders bei großen oder zeilenweise aufgebauten Daten wie NDJSON, CSV oder Logdateien.

Typische Einsatzorte sind Service Worker, die abgefangene fetch-Anfragen untersuchen, und serverseitige Laufzeitumgebungen mit Fetch-API (Handler, die ein Request-Objekt bekommen). Wie bei allen Body-Methoden gilt: Der Body kann nur einmal gelesen werden. Wenn du ihn mehrfach brauchst, klone die Anfrage vorher mit request.clone().

Rückgabewert

Typ
ReadableStream<string>
Beschreibung
Ein ReadableStream, dessen Chunks UTF-8-dekodierte Zeichenketten sind. Hat die Anfrage keinen Body (body === null), wird ein leerer Stream erwartet. Ist der Body schon gelesen oder gesperrt, wird ein TypeError geworfen.

Beispiele

Request-Body stückweise als Text lesen

const request = new Request('/upload', {
  method: 'POST',
  body: 'Hallo Welt – Grüße aus Köln!'
});

const reader = request.textStream().getReader();
let text = '';

while (true) {
  const { done, value } = await reader.read();
  if (done) break;
  text += value; // value ist bereits ein String
}

console.log(text);
Hallo Welt – Grüße aus Köln!

Mit Feature-Erkennung und Fallback über TextDecoderStream

// Liefert immer einen String-Stream, auch ohne textStream()-Unterstützung
const getTextStream = (request) =>
  typeof request.textStream === 'function'
    ? request.textStream()
    : request.body.pipeThrough(new TextDecoderStream());

const req = new Request('/api', { method: 'POST', body: 'a,b,c\n1,2,3' });
const reader = getTextStream(req).getReader();
const { value } = await reader.read();
console.log(typeof value, value);
string a,b,c 1,2,3

NDJSON im Service Worker zeilenweise verarbeiten

self.addEventListener('fetch', (event) => {
  const { request } = event;
  if (request.method !== 'POST' || !request.url.endsWith('/events')) return;

  event.respondWith((async () => {
    // Klonen, damit das Original weitergeleitet werden kann
    const reader = request.clone().textStream().getReader();
    let buffer = '';
    let count = 0;

    while (true) {
      const { done, value } = await reader.read();
      if (done) break;
      buffer += value;
      const lines = buffer.split('\n');
      buffer = lines.pop(); // unvollständige Zeile aufheben
      for (const line of lines) {
        if (line.trim()) {
          JSON.parse(line);
          count++;
        }
      }
    }
    if (buffer.trim()) count++;

    console.log(`${count} Ereignisse empfangen`);
    return fetch(request);
  })());
});
3 Ereignisse empfangen

// Wichtig · Fallstricke

  • Kompatibilität: textStream() ist sehr neu und experimentell, die meisten Browser und Laufzeitumgebungen unterstützen es noch nicht. Prüfe deshalb vorher mit typeof request.textStream === 'function' und nutze sonst request.body.pipeThrough(new TextDecoderStream()) als Ersatz, der überall funktioniert.
  • Nur einmal lesbar: Nach dem Aufruf gilt der Body als verbraucht (request.bodyUsed). Ein späterer Aufruf von text(), json() oder textStream() wirft einen TypeError. Brauchst du den Body mehrfach, rufe vorher request.clone() auf.
  • Immer UTF-8: Die Dekodierung erfolgt immer als UTF-8, der charset im Content-Type-Header wird ignoriert. Für andere Kodierungen verwende new TextDecoderStream('iso-8859-1') und Ähnliches.
  • Chunk-Grenzen: Chunks halten sich nicht an Zeilen- oder JSON-Grenzen. Für zeilenweise Verarbeitung musst du einen eigenen Puffer führen (siehe Beispiel).
  • Die asynchrone Iteration mit for await (const chunk of stream) ist bequemer, wird aber nicht von allen Browsern unterstützt. getReader() funktioniert überall.