Signatur
Beschreibung
Die schreibgeschützte Eigenschaft incomingBidirectionalStreams des WebTransport-Interfaces liefert einen ReadableStream. Jeder Chunk dieses Streams ist ein WebTransportBidirectionalStream, also ein Kanal, den der Server geöffnet hat. Jedes dieser Objekte hat einen readable-Teil (WebTransportReceiveStream) zum Lesen und einen writable-Teil (WebTransportSendStream) zum Schreiben.
Die Eigenschaft ist für Protokolle gedacht, bei denen der Server von sich aus Anfrage-Antwort-Austausche startet, z. B. Server-seitige RPC-Aufrufe, Push-Anfragen mit Bestätigung oder Multiplayer-Sitzungen mit eigenen Kanälen pro Spieler oder Objekt. Streams, die der Client selbst öffnen will, erzeugt man dagegen mit WebTransport.prototype.createBidirectionalStream().
In der Regel liest man den Stream in einer Schleife mit getReader() und read() aus, bis done den Wert true hat. Jeden eingehenden Stream verarbeitet man dann unabhängig und asynchron, damit ein langsamer Kanal die anderen nicht blockiert. Mit dem Lesen sollte man erst beginnen, wenn transport.ready erfüllt ist.
Rückgabewert
ReadableStream, dessen Chunks WebTransportBidirectionalStream-Objekte mit den Eigenschaften readable und writable sind.Beispiele
Eingehende bidirektionale Streams annehmen
const transport = new WebTransport('https://example.com:4999/wt');
await transport.ready;
const reader = transport.incomingBidirectionalStreams.getReader();
while (true) {
const { value: bidiStream, done } = await reader.read();
if (done) {
console.log('Keine weiteren Streams vom Server.');
break;
}
// Jeden Stream getrennt verarbeiten, nicht mit await blockieren
handleStream(bidiStream);
}
async function handleStream({ readable, writable }) {
console.log('Neuer Stream vom Server geöffnet');
// ... siehe nächstes Beispiel
}
Server-Anfrage lesen und beantworten (Echo/RPC)
const decoder = new TextDecoder();
const encoder = new TextEncoder();
async function handleStream({ readable, writable }) {
// Komplette Anfrage des Servers lesen
let text = '';
for await (const chunk of readable) {
text += decoder.decode(chunk, { stream: true });
}
console.log('Anfrage:', text);
// Antwort über denselben Stream zurückschicken
const writer = writable.getWriter();
await writer.write(encoder.encode(`ACK: ${text}`));
await writer.close();
}
Mit for await und Fehlerbehandlung
const transport = new WebTransport('https://example.com:4999/wt');
try {
await transport.ready;
for await (const stream of transport.incomingBidirectionalStreams) {
handleStream(stream).catch((err) =>
console.error('Fehler in Stream:', err)
);
}
} catch (err) {
console.error('Verbindung fehlgeschlagen oder abgebrochen:', err);
} finally {
const info = await transport.closed.catch(() => ({}));
console.log('Transport geschlossen', info);
}
// Wichtig · Fallstricke
- Browser-Unterstützung: WebTransport gibt es in Chromium-Browsern ab Version 97 und in Firefox ab Version 114. Safari unterstützt es erst ab Version 26.4. Die Eigenschaft ist nur in einem sicheren Kontext (HTTPS) und über HTTP/3 verfügbar. Vorher mit
'WebTransport' in globalThisprüfen. - Asynchrone Iteration:
for await...ofdirekt auf einemReadableStreamfunktioniert nicht in allen Browsern. Als RückfallebenegetReader()mitread()verwenden. - Nicht blockieren: Wenn man innerhalb der Leseschleife auf die Verarbeitung eines Streams wartet (
await handleStream()), werden alle weiteren Streams verzögert. Stattdessen parallel verarbeiten. - Nur ein Reader: Solange ein Reader existiert, ist der Stream gesperrt (
locked). Ein zweiter Aufruf vongetReader()wirft einenTypeError. - Beim Schließen: Wird der Transport mit
close()geschlossen, endet der Stream (done: true). Bei einem Verbindungsfehler wird er dagegen mit einem Fehler abgebrochen, deshalb immertry/catchnutzen. - Der Server bestimmt, wie viele Streams er gleichzeitig öffnet. Der Client sollte deshalb Grenzen setzen oder nicht benötigte Streams gezielt mit
readable.cancel()bzw.writable.abort()beenden.