Veröffentlicht am 8. Juni 2020
WebTransport ist eine Web-API, die das HTTP/3-Protokoll als bidirektionalen Transport verwendet. Sie ist für die bidirektionale Kommunikation zwischen einem Webclient und einem HTTP/3-Server vorgesehen. Sie unterstützt das Senden von Daten sowohl unzuverlässig mit den Datagram-APIs als auch zuverlässig mit den Streams-APIs.
Datagramme eignen sich ideal zum Senden und Empfangen von Daten, für die keine starken Zustellgarantien erforderlich sind. Die Größe einzelner Datenpakete ist durch die maximale Übertragungseinheit (Maximum Transmission Unit, MTU) der zugrunde liegenden Verbindung begrenzt. Sie werden möglicherweise nicht erfolgreich übertragen und können, wenn sie übertragen werden, in beliebiger Reihenfolge eintreffen. Diese Eigenschaften machen die Datagram-APIs ideal für die Datenübertragung mit geringer Latenz und Best-Effort-Zustellung. Sie können sich Datagramme als UDP-Nachrichten (User Datagram Protocol) vorstellen, die jedoch verschlüsselt und mit Überlastkontrolle sind.
Die Streams-APIs hingegen bieten eine zuverlässige, geordnete Datenübertragung. Sie eignen sich gut für Szenarien, in denen Sie einen oder mehrere Streams mit geordneten Daten senden oder empfangen müssen. Die Verwendung mehrerer WebTransport-Streams ist vergleichbar mit dem Herstellen mehrerer TCP-Verbindungen. Da HTTP/3 jedoch das leichtere QUIC-Protokoll verwendet, können sie ohne großen Aufwand geöffnet und geschlossen werden.
Anwendungsfälle
Hier ist eine kleine Liste mit möglichen Anwendungsfällen für WebTransport.
- Spielstatus in regelmäßigen Abständen mit minimaler Latenz an einen Server senden, in kleinen, unzuverlässigen, ungeordneten Nachrichten.
- Medienstreams mit minimaler Latenz von einem Server empfangen, unabhängig von anderen Datenstreams.
- Benachrichtigungen von einem Server empfangen, während eine Webseite geöffnet ist.
Wir würden gerne mehr darüber erfahren, wie Sie WebTransport verwenden möchten.
Unterstützte Browser
Wie bei allen Funktionen, die nicht von allen Browsern unterstützt werden, empfehlen wir, die Funktionserkennung hinzuzufügen.
Beziehung zu anderen Technologien
Ist WebTransport ein Ersatz für WebSockets?
Vielleicht. Es gibt Anwendungsfälle, in denen entweder WebSockets oder WebTransport als gültige Kommunikationsprotokolle verwendet werden können.
Die WebSockets-Kommunikation basiert auf einem einzelnen, zuverlässigen, geordneten Nachrichtenstream, der für einige Arten von Kommunikationsanforderungen geeignet ist. Wenn Sie diese Eigenschaften benötigen, können Sie sie auch mit den Streams-APIs von WebTransport erhalten. Im Vergleich dazu bieten die Datagram-APIs von WebTransport eine Zustellung mit geringer Latenz, ohne Garantien für Zuverlässigkeit oder Reihenfolge. Sie sind also kein direkter Ersatz für WebSockets.
Wenn Sie WebTransport mit den Datagram-APIs oder mehreren gleichzeitigen Streams API-Instanzen verwenden, müssen Sie sich keine Gedanken über das Head-of-Line-Blocking machen, das bei WebSockets ein Problem sein kann. Außerdem gibt es Leistungsvorteile beim Herstellen neuer Verbindungen, da der zugrunde liegende QUIC-Handshake schneller ist als das Starten von TCP über TLS.
WebTransport ist Teil einer neuen Spezifikationsversion. Daher ist das WebSockets-Ökosystem rund um Client- und Serverbibliotheken viel robuster. Wenn Sie etwas benötigen, das sofort mit gängigen Servereinstellungen und mit breiter Webclient-Unterstützung funktioniert, ist WebSockets derzeit die bessere Wahl.
Ist WebTransport dasselbe wie eine UDP-Socket-API?
Nein. WebTransport ist keine UDP-Socket-API. WebTransport verwendet zwar HTTP/3, das wiederum UDP verwendet, aber WebTransport hat Anforderungen an Verschlüsselung und Überlastkontrolle, die es zu mehr als einer einfachen UDP-Socket-API machen.
Ist WebTransport eine Alternative zu WebRTC-Datenkanälen?
Ja, für Client-Server-Verbindungen. WebTransport hat viele der gleichen Eigenschaften wie WebRTC-Datenkanäle, obwohl die zugrunde liegenden Protokolle unterschiedlich sind.
Im Allgemeinen erfordert das Ausführen eines HTTP/3-kompatiblen Servers weniger Einrichtung und Konfiguration als das Verwalten eines WebRTC-Servers, bei dem mehrere Protokolle (ICE, DTLS und SCTP) verstanden werden müssen, um einen funktionierenden Transport zu erhalten. WebRTC umfasst viel mehr bewegliche Teile, die zu fehlgeschlagenen Client-Server-Verhandlungen führen können.
Die WebTransport API wurde speziell für Webentwickler entwickelt und sollte sich eher wie das Schreiben von modernem Webplattformcode anfühlen als die Verwendung der Datenkanalschnittstellen von WebRTC. Im Gegensatz zu WebRTC wird WebTransport in Web Workers unterstützt. So können Sie Client-Server-Kommunikation unabhängig von einer bestimmten HTML-Seite durchführen. Da WebTransport eine Streams-konforme Schnittstelle bereitstellt, werden Optimierungen im Zusammenhang mit Backpressure unterstützt.
Wenn Sie jedoch bereits eine funktionierende WebRTC-Client-Server-Einrichtung haben, mit der Sie zufrieden sind, bietet der Wechsel zu WebTransport möglicherweise nicht viele Vorteile.
Test
Die beste Möglichkeit, WebTransport zu testen, besteht darin, einen kompatiblen HTTP/3-Server zu starten. Verwenden Sie diese Seite mit einem einfachen JavaScript-Client, um die Client- und Serverkommunikation zu testen.
Außerdem ist unter webtransport.day ein von der Community verwalteter Echoserver verfügbar.
API verwenden
WebTransport wurde auf modernen Webplattform-Primitiven wie der Streams API entwickelt. Es basiert stark auf Promises und funktioniert gut mit async und await.
Die aktuelle WebTransport-Implementierung in Chromium unterstützt drei verschiedene Arten von Traffic: Datagramme sowie unidirektionale und bidirektionale Streams.
Verbindung zu einem Server herstellen
Sie können eine Verbindung zu einem HTTP/3-Server herstellen, indem Sie eine WebTransport-Instanz erstellen. Das Schema der URL sollte https sein. Sie müssen die Portnummer explizit angeben.
Verwenden Sie das ready-Promise, um zu warten, bis die Verbindung hergestellt ist.
Dieses Promise bleibt unerfüllt, bis die Einrichtung abgeschlossen ist, und wird abgelehnt, wenn die Verbindung in der QUIC/TLS-Phase fehlschlägt.
Das closed-Promise wird erfüllt, wenn die Verbindung normal geschlossen wird, und wird abgelehnt, wenn das Schließen unerwartet war.
Wenn der Server die Verbindung aufgrund eines
Client-Anzeigefehlers
ablehnt (z. B. wenn der Pfad der URL ungültig ist), wird closed abgelehnt, während ready nicht aufgelöst wird.
const url = 'https://example.com:4999/foo/bar';
const transport = new WebTransport(url);
// Optionally, set up functions to respond to
// the connection closing:
transport.closed.then(() => {
console.log(`The HTTP/3 connection to ${url} closed gracefully.`);
}).catch((error) => {
console.error(`The HTTP/3 connection to ${url} closed due to ${error}.`);
});
// Once .ready fulfills, the connection can be used.
await transport.ready;
Datagram-APIs
Sobald Sie eine WebTransport-Instanz haben, die mit einem Server verbunden ist, können Sie damit einzelne Datenbits senden und empfangen, die als Datagramme bezeichnet werden.
Der writeable Getter gibt einen WritableStream zurück, mit dem ein Webclient Daten an den Server senden kann. Der Getter readable gibt einen ReadableStream zurück, mit dem Sie auf Daten vom Server warten können. Beide Streams sind von Natur aus unzuverlässig. Es ist also möglich, dass die von Ihnen geschriebenen Daten nicht vom Server empfangen werden und umgekehrt.
Beide Streamtypen verwenden Uint8Array-Instanzen für die Datenübertragung.
// Send two datagrams to the server.
const writer = transport.datagrams.writable.getWriter();
const data1 = new Uint8Array([65, 66, 67]);
const data2 = new Uint8Array([68, 69, 70]);
writer.write(data1);
writer.write(data2);
// Read datagrams from the server.
const reader = transport.datagrams.readable.getReader();
while (true) {
const {value, done} = await reader.read();
if (done) {
break;
}
// value is a Uint8Array.
console.log(value);
}
Streams-APIs
Sobald Sie eine Verbindung zum Server hergestellt haben, können Sie WebTransport auch verwenden, um Daten über die Streams-APIs zu senden und zu empfangen.
Jeder Chunk aller Streams ist ein Uint8Array. Im Gegensatz zu den Datagram-APIs sind diese Streams zuverlässig. Jeder Stream ist jedoch unabhängig, daher ist die Reihenfolge der Daten über Streams hinweg nicht garantiert.
WebTransportSendStream
Ein WebTransportSendStream wird vom Webclient mit der Methode createUnidirectionalStream() einer WebTransport-Instanz erstellt, die ein Promise für den WebTransportSendStream zurückgibt.
Verwenden Sie die close() Methode des WritableStreamDefaultWriter, um den zugehörigen HTTP/3-Stream zu schließen. Der Browser versucht, alle ausstehenden Daten zu senden, bevor der zugehörige Stream tatsächlich geschlossen wird.
// Send two Uint8Arrays to the server.
const stream = await transport.createUnidirectionalStream();
const writer = stream.writable.getWriter();
const data1 = new Uint8Array([65, 66, 67]);
const data2 = new Uint8Array([68, 69, 70]);
writer.write(data1);
writer.write(data2);
try {
await writer.close();
console.log('All data has been sent.');
} catch (error) {
console.error(`An error occurred: ${error}`);
}
Verwenden Sie entsprechend die abort() Methode des WritableStreamDefaultWriter, um ein RESET_STREAM an den Server zu senden. Bei Verwendung von abort() verwirft der Browser möglicherweise alle ausstehenden Daten, die noch nicht gesendet wurden.
const ws = await transport.createUnidirectionalStream();
const writer = ws.getWriter();
writer.write(...);
writer.write(...);
await writer.abort();
// Not all the data may have been written.
WebTransportReceiveStream
Der Server initiiert WebTransportReceiveStream.
Das Abrufen eines WebTransportReceiveStream ist für einen Webclient ein zweistufiger Prozess. Zuerst ruft der Client das Attribut incomingUnidirectionalStreams einer WebTransport-Instanz auf, das einen ReadableStream zurückgibt. Jeder Chunk dieses ReadableStream ist wiederum ein WebTransportReceiveStream, mit dem Uint8Array-Instanzen gelesen werden können, die vom Server gesendet wurden.
async function readFrom(receiveStream) {
const reader = receiveStream.readable.getReader();
while (true) {
const {done, value} = await reader.read();
if (done) {
break;
}
// value is a Uint8Array
console.log(value);
}
}
const rs = transport.incomingUnidirectionalStreams;
const reader = rs.getReader();
while (true) {
const {done, value} = await reader.read();
if (done) {
break;
}
// value is an instance of WebTransportReceiveStream
await readFrom(value);
}
Sie können das Schließen des Streams mit dem closed-Promise des ReadableStreamDefaultReader erkennen. Wenn der zugrunde liegende HTTP/3-Stream mit dem FIN-Bit geschlossen wird, wird das closed Promise erfüllt, nachdem alle Daten gelesen wurden. Wenn der HTTP/3-Stream abrupt geschlossen wird (z. B. durch RESET_STREAM), wird das closed Promise abgelehnt.
// Assume an active receiveStream
const reader = receiveStream.readable.getReader();
reader.closed.then(() => {
console.log('The receiveStream closed gracefully.');
}).catch(() => {
console.error('The receiveStream closed abruptly.');
});
WebTransportBidirectionalStream
Ein WebTransportBidirectionalStream
kann entweder vom Server oder vom Client erstellt werden.
Webclients können einen mit der createBidirectionalStream() Methode einer
WebTransport Instanz erstellen, die ein Promise für einen
WebTransportBidirectionalStream zurückgibt.
const stream = await transport.createBidirectionalStream();
// stream is a WebTransportBidirectionalStream
// stream.readable is a ReadableStream
// stream.writable is a WritableStream
Sie können mit dem Attellribut incomingBidirectionalStreams einer WebTransport-Instanz auf einen vom Server erstellten WebTransportBidirectionalStream warten, der einen ReadableStream zurückgibt. Jeder Chunk dieses ReadableStream ist wiederum ein WebTransportBidirectionalStream.
const rs = transport.incomingBidirectionalStreams;
const reader = rs.getReader();
while (true) {
const {done, value} = await reader.read();
if (done) {
break;
}
// value is a WebTransportBidirectionalStream
// value.readable is a ReadableStream
// value.writable is a WritableStream
}
Ein WebTransportBidirectionalStream ist nur eine Kombination aus einem WebTransportSendStream und WebTransportReceiveStream. In den Beispielen aus den beiden vorherigen Abschnitten wird erläutert, wie die einzelnen Streams verwendet werden.
Polyfill
Es ist ein Polyfill (oder besser Ponyfill, das Funktionen als eigenständiges Modul bereitstellt) namens
webtransport-ponyfill-websocket
verfügbar, das einige der Funktionen von WebTransport implementiert. Lesen Sie die Einschränkungen in der README-Datei des Projekts sorgfältig durch, um festzustellen, ob diese Lösung für Ihren Anwendungsfall geeignet ist.
Datenschutz- und Sicherheitsaspekte
Eine maßgebliche Anleitung finden Sie im entsprechenden Abschnitt der Spezifikationsversion.
Feedback
Gibt es etwas an der API, das umständlich ist oder nicht wie erwartet funktioniert? Oder fehlen Ihnen Teile, die Sie zur Umsetzung Ihrer Idee benötigen?
- Melden Sie ein Problem im Web Transport-GitHub-Repository, oder fügen Sie Ihre Gedanken zu einem vorhandenen Problem hinzu.
- Melden Sie einen Fehler bei der Chromium-Implementierung. Geben Sie so viele Details wie möglich an und fügen Sie eine Anleitung zur Reproduktion hinzu.
Ihre öffentliche Unterstützung hilft Chrome, Funktionen zu priorisieren, und zeigt anderen Browseranbietern, wie wichtig es ist, sie zu unterstützen.
- Twittern Sie @ChromiumDev mit dem Hashtag
#WebTransportund geben Sie an, wo und wie Sie es verwenden.
Allgemeine Disussionen
Sie können die Google-Gruppe web-transport-dev für allgemeine Fragen oder Probleme verwenden, die nicht in eine der anderen Kategorien passen.
Danksagungen
Wir haben Informationen aus dem WebTransport Explainer und der Spezifikationsversionaufgenommen. Vielen Dank an die jeweiligen Autoren für die Bereitstellung dieser Grundlage.