Signatur
Beschreibung
Die Eigenschaft incomingUnidirectionalStreams einer WebTransport-Verbindung ist ein ReadableStream, dessen einzelne Einträge selbst wieder Streams sind: Jedes Mal, wenn der Server einen neuen unidirektionalen Stream öffnet (Server → Client), taucht hier ein WebTransportReceiveStream auf – ein ReadableStream mit Bytes (Uint8Array-Blöcken).
Unidirektionale Streams eignen sich für Daten, die nur in eine Richtung fließen, z. B. Push-Nachrichten, Spielzustände, Log-Ströme oder Mediensegmente. Anders als Datagramme sind sie zuverlässig und geordnet – innerhalb eines Streams. Mehrere Streams laufen dank QUIC unabhängig voneinander, sodass ein verlorenes Paket in einem Stream die anderen nicht blockiert (kein Head-of-Line-Blocking).
Typischerweise liest man die Eigenschaft in einer Schleife mit getReader() oder for await...of aus und verarbeitet jeden eingehenden Stream in einer eigenen, nicht abgewarteten asynchronen Funktion, damit ein langsamer Stream die Annahme weiterer Streams nicht aufhält. Für die Gegenrichtung (Client → Server) nutzt man WebTransport.createUnidirectionalStream().
Rückgabewert
ReadableStream, dessen Einträge WebTransportReceiveStream-Objekte sind (je ein vom Server geöffneter unidirektionaler Stream). Er wird geschlossen, wenn die Verbindung endet, bzw. mit Fehler abgebrochen, wenn sie fehlschlägt.Beispiele
Eingehende Streams mit getReader() annehmen
const transport = new WebTransport('https://example.com:4433/push');
await transport.ready;
const readStream = async (stream) => {
const reader = stream.getReader();
const decoder = new TextDecoder();
let text = '';
while (true) {
const { value, done } = await reader.read();
if (done) break;
text += decoder.decode(value, { stream: true });
}
text += decoder.decode();
console.log('Stream empfangen:', text);
};
const streams = transport.incomingUnidirectionalStreams.getReader();
while (true) {
const { value: stream, done } = await streams.read();
if (done) {
console.log('Keine weiteren Streams.');
break;
}
// Nicht abwarten: parallel weitere Streams annehmen
readStream(stream).catch((err) => console.error('Stream-Fehler:', err));
}
Kompakt mit for await...of und JSON-Nachrichten
const transport = new WebTransport('https://game.example.com:4433/state');
await transport.ready;
const handleStream = async (stream) => {
const text = await new Response(stream).text();
const update = JSON.parse(text);
console.log('Spielzustand:', update.tick, update.players.length);
};
// ReadableStream ist in modernen Browsern async-iterierbar
for await (const stream of transport.incomingUnidirectionalStreams) {
handleStream(stream).catch(console.error);
}
Verbindungsende und Abbruch sauber behandeln
const transport = new WebTransport('https://example.com:4433/logs');
transport.closed
.then(({ closeCode, reason }) => console.log('Geschlossen:', closeCode, reason))
.catch((err) => console.warn('Verbindung abgebrochen:', err.message));
try {
await transport.ready;
const reader = transport.incomingUnidirectionalStreams.getReader();
const { value: stream } = await reader.read();
// Nur den ersten Stream lesen, danach nicht mehr interessiert
await stream.cancel('Nicht mehr benötigt');
reader.releaseLock();
transport.close({ closeCode: 0, reason: 'Fertig' });
} catch (err) {
console.error('Fehler:', err);
}
// Wichtig · Fallstricke
- Parallel verarbeiten: Wird jeder eingehende Stream mit
awaitvollständig gelesen, bevor der nächste angenommen wird, stauen sich Streams an – und der Server kann durch Flusskontrolle blockiert werden. Einzelne Streams daher in eigenen Promises verarbeiten. - Nur ein Reader: Der Stream kann nur von einem Reader gleichzeitig gesperrt werden; ein zweites
getReader()wirft einenTypeError, solange der erste nicht perreleaseLock()freigegeben ist. - Fehler: Bricht die Verbindung ab, wird der Stream mit einem Fehler (meist
WebTransportError) beendet –read()bzw.for awaitwerfen dann. Immertry/catchbzw.transport.closedbehandeln. - Kompatibilität: Nur in sicheren Kontexten (HTTPS) verfügbar, erfordert einen HTTP/3-Server mit WebTransport-Unterstützung. Chromium seit Version 97, Firefox seit 114; Safari erst in neueren Versionen – vorher per
'WebTransport' in globalThisprüfen. Asynchrone Iteration überReadableStream(for await) ist in Safari erst spät verfügbar; im ZweifelgetReader()nutzen. - Streams, die man nicht braucht, mit
stream.cancel()beenden, damit der Server keine Ressourcen verschwendet.