Korzystanie z WebTransport

WebTransport to interfejs API zapewniający dwukierunkowe przesyłanie wiadomości między klientem a serwerem z minimalnym opóźnieniem. Dowiedz się więcej o przypadkach użycia i o tym, jak przesłać opinię na temat przyszłej implementacji.

Tło

Co to jest WebTransport?

WebTransport to interfejs API internetowy, który używa protokołu HTTP/3 jako dwukierunkowego transportu. Jest przeznaczony do komunikacji dwukierunkowej między klientem internetowym a serwerem HTTP/3. Umożliwia wysyłanie danych niewiarygodnie za pomocą interfejsów datagram API oraz niezawodnie za pomocą interfejsów stream API.

Datagramy są idealne do wysyłania i odbierania danych, które nie wymagają mocnych gwarancji dostarczenia. Poszczególne pakiety danych są ograniczone rozmiarem przez maksymalną jednostkę przesyłania (MTU) podstawowego połączenia. Mogą być przesyłane pomyślnie lub nie. Jeśli zostaną przesłane, mogą dotrzeć w dowolnej kolejności. Dzięki tym cechom interfejsy API datagramów są idealne do przesyłania danych z minimalnym opóźnieniem i z zachowaniem najwyższej staranności. Dane te można traktować jako wiadomości protokołu pakietów użytkownika (UDP), ale zaszyfrowane i kontrolowane pod kątem natężenia ruchu.

Interfejsy API strumieni zapewniają natomiast niezawodny, uporządkowany transfer danych. Są dobrze dostosowane do sytuacji, w których trzeba wysyłać lub odbierać co najmniej 1 strumień uporządkowanych danych. Używanie wielu strumieni WebTransport jest analogiczne do nawiązywania wielu połączeń TCP, ale ponieważ HTTP/3 używa lżejszego protokołu QUIC, można je otwierać i zamykać bez nadmiernego narzutu.

Przypadki użycia

Oto krótka lista możliwych sposobów korzystania z WebTransport przez programistów.

  • Wysyłanie stanu gry w określonych odstępach czasu z minimalnym opóźnieniem na serwer za pomocą małych, niepewnych i nieuporządkowanych wiadomości.
  • Odbieranie strumieni multimediów przesyłanych z serwera z minimalnym opóźnieniem, niezależnie od innych strumieni danych.
  • otrzymywanie powiadomień wysyłanych przez serwer, gdy strona internetowa jest otwarta;

Chcielibyśmy wiedzieć więcej o tym, jak planujesz używać WebTransport.

Obsługa przeglądarek

Obsługa przeglądarek

  • Chrome: 97.
  • Edge: 97.
  • Firefox: 114.
  • Safari: nieobsługiwane.

Źródło

Podobnie jak w przypadku wszystkich funkcji, które nie są obsługiwane przez wszystkie przeglądarki, zalecamy stosowanie wykrywania funkcji.

Obecny stan,

Krok Stan
1. Tworzenie wyjaśnienia Zakończono
2. Tworzenie wstępnej wersji specyfikacji Zakończono
3. Zbieraj opinie i ulepszaj projekt Zakończone
4. Wersja próbna origin Zakończone
5. Wprowadzenie na rynek Chromium 97

Związek WebTransport z innymi technologiami

Czy WebTransport zastępuje WebSockets?

Być może. W niektórych przypadkach można użyć protokołów WebSockets lub WebTransport.

Komunikacja za pomocą WebSockets opiera się na jednym niezawodnym uporządkowanym strumieniu wiadomości, co jest odpowiednie w przypadku niektórych potrzeb komunikacyjnych. Jeśli potrzebujesz tych cech, możesz je uzyskać za pomocą interfejsów API strumieni WebTransport. Dla porównania: interfejsy API datagramów WebTransport zapewniają przesyłanie z niskim opóźnieniem, ale bez gwarancji niezawodności ani kolejności, więc nie zastępują bezpośrednio WebSocketów.

Korzystanie z WebTransport za pomocą interfejsów API datagramów lub wielu równoczesnych instancji interfejsu Streams API oznacza, że nie musisz się martwić o blokowanie na froncie, które może być problemem w przypadku WebSockets. Dodatkowo uzyskujesz korzyści związane z wydajnością podczas nawiązywania nowych połączeń, ponieważ uściślenie QUIC jest szybsze niż uruchamianie TCP przez TLS.

WebTransport jest częścią nowego projektu specyfikacji, dlatego ekosystem WebSocket dotyczący bibliotek klienckich i serwerowych jest obecnie znacznie bardziej niezawodny. Jeśli potrzebujesz czegoś, co działa „od razu” w przypadku typowych konfiguracji serwera i obsługuje szeroką gamę klientów internetowych, obecnie lepszym wyborem jest WebSockets.

Czy WebTransport to to samo co interfejs UDP Socket API?

Nie. WebTransport nie jest interfejsem UDP Socket API. WebTransport używa HTTP/3, który z kolei używa UDP „pod spodem”, ale ma też wymagania dotyczące szyfrowania i kontroli natężenia, dzięki czemu jest czymś więcej niż podstawowy interfejs UDP Socket API.

Czy WebTransport jest alternatywą dla kanałów danych WebRTC?

Tak, w przypadku połączeń klient-serwer. WebTransport ma wiele takich samych właściwości co kanały danych WebRTC, ale jego protokoły są inne.

Zazwyczaj obsługa serwera zgodnego z HTTP/3 wymaga mniej konfiguracji niż serwera WebRTC, który wymaga znajomości wielu protokołów (ICE, DTLSSCTP) w celu zapewnienia działającego transportu. WebRTC wymaga wielu elementów, które mogą prowadzić do niepowodzenia negocjacji między klientem a serwerem.

Interfejs WebTransport API został zaprojektowany z myślą o programistach i powinien przypominać tworzenie kodu dla nowoczesnych platform internetowych, a nie interfejsy kanału danych WebRTC. W przeciwieństwie do WebRTC WebTransport jest obsługiwany w Web Workers, co umożliwia komunikację klienta z serwerem niezależnie od danej strony HTML. WebTransport udostępnia interfejs zgodny z Streams, więc obsługuje optymalizacje związane z ciśnieniem zwrotnym.

Jeśli jednak masz już działającą konfigurację klienta/serwera WebRTC, która Ci odpowiada, przejście na WebTransport może nie przynieść wielu korzyści.

Wypróbuj

Najlepszym sposobem na eksperymentowanie z WebTransport jest uruchomienie zgodnego serwera HTTP/3. Następnie możesz użyć tej strony z podstawowym klientem JavaScript, aby przetestować komunikację między klientem a serwerem.

Dodatkowo serwer echo obsługiwany przez społeczność jest dostępny pod adresem webtransport.day.

Korzystanie z interfejsu API

Interfejs WebTransport został zaprojektowany na podstawie nowoczesnych prymitywów platformy internetowej, takich jak Streams API. W dużej mierze opiera się na obietnicach i dobrze współpracuje ze znacznikami asyncawait.

Obecna implementacja WebTransport w Chromium obsługuje 3 różne typy ruchu: datagramy oraz strumienie jednokierunkowe i dwukierunkowe.

Łączenie z serwerem

Aby połączyć się z serwerem HTTP/3, utwórz instancję WebTransport. Schemat adresu URL powinien być https. Musisz wyraźnie podać numer portu.

Użyj ready, aby poczekać na nawiązanie połączenia. Ta obietnica nie zostanie spełniona, dopóki konfiguracja nie zostanie ukończona, a jeśli połączenie nie powiedzie się na etapie QUIC/TLS, zostanie odrzucone.

Obietnica closed jest spełniana, gdy połączenie jest zamykane normalnie, i odrzucana, gdy zamknięcie jest nieoczekiwane.

Jeśli serwer odrzuci połączenie z powodu błędu wskazania klienta (np. nieprawidłowa ścieżka adresu URL), closed zostanie odrzucone, a ready pozostanie nierozwiązane.

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;

Interfejsy Datagram API

Gdy masz instancję WebTransport połączoną z serwerem, możesz jej używać do wysyłania i odbierania oddzielnych bitów danych, zwanych datagrams.

Getter writeable zwraca WritableStream, którego klient WWW może użyć do wysłania danych na serwer. Getter readable zwraca ReadableStream, co umożliwia nasłuchiwanie danych z serwera. Oba strumienie są z zasady niewiarygodne, więc możliwe, że serwer nie otrzyma danych, które zapiszesz, i odwrotnie.

Oba typy strumieni korzystają z instancji Uint8Array do przenoszenia danych.

// 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);
}

Interfejsy Streams API

Po połączeniu z serwerem możesz też używać WebTransport do wysyłania i odbierania danych za pomocą interfejsów Streams API.

Każdy fragment wszystkich strumieni to Uint8Array. W przeciwieństwie do interfejsów Datagram API te strumienie są niezawodne. Każdy strumień jest jednak niezależny, więc kolejność danych w różnych strumieniach nie jest gwarantowana.

WebTransportSendStream

Klient internetowy tworzy obiekt WebTransportSendStream, używając metody createUnidirectionalStream() instancji WebTransport, która zwraca obietnicę dla WebTransportSendStream.

Aby zamknąć powiązane połączenie HTTP/3, użyj metody close() obiektu WritableStreamDefaultWriter. Przed zamknięciem powiązanego połączenia przeglądarka próbuje wysłać wszystkie oczekujące dane.

// 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}`);
}

Podobnie użyj metody abort() klasy WritableStreamDefaultWriter, aby wysłać na serwer obiekt RESET\_STREAM. Podczas korzystania z funkcji abort() przeglądarka może odrzucić wszystkie oczekujące dane, które nie zostały jeszcze wysłane.

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

WebTransportReceiveStream jest inicjowane przez serwer. W przypadku klienta internetowego uzyskanie WebTransportReceiveStream to proces dwuetapowy. Najpierw wywołuje atrybut incomingUnidirectionalStreams wystąpienia WebTransport, który zwraca ReadableStream. Każdy fragment tego ReadableStream jest z kolei WebTransportReceiveStream, który może być używany do odczytu instancji Uint8Array wysłanych przez serwer.

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);
}

Możesz wykryć zamknięcie strumienia za pomocą obietnicy closed w ReadableStreamDefaultReader. Gdy podstawowe połączenie HTTP/3 jest zamykane za pomocą bitu FIN, closed obietnica jest spełniana po odczytaniu wszystkich danych. Gdy połączenie HTTP/3 zostanie zamknięte nagle (na przykład przez RESET\_STREAM), closed promise zostanie odrzucone.

// 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

WebTransportBidirectionalStream może zostać utworzona przez serwer lub klienta.

Klienci internetowi mogą utworzyć jeden za pomocą metody createBidirectionalStream() instancji WebTransport, która zwraca obietnicę dla WebTransportBidirectionalStream.

const stream = await transport.createBidirectionalStream();
// stream is a WebTransportBidirectionalStream
// stream.readable is a ReadableStream
// stream.writable is a WritableStream

Możesz nasłuchiwać WebTransportBidirectionalStream utworzonego przez serwer za pomocą atrybutu incomingBidirectionalStreams instancji WebTransport, który zwraca ReadableStream. Każdy fragment tego ReadableStream jest z kolei 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
}

WebTransportBidirectionalStream to tylko kombinacja WebTransportSendStreamWebTransportReceiveStream. Przykłady z poprzednich 2 sekcji pokazują, jak używać poszczególnych metod.

Więcej przykładów

Projekt specyfikacji WebTransport zawiera kilka dodatkowych przykładów w tekście oraz pełną dokumentację wszystkich metod i właściwości.

WebTransport w Narzędziach deweloperskich w Chrome

Narzędzia deweloperskie w Chrome nie obsługują obecnie WebTransport. Możesz „oznaczyć gwiazdką” ten problem w Chrome, aby otrzymywać powiadomienia o aktualizacjach w interfejsie Narzędzi deweloperskich.

Watolina

Dostępny jest polyfill (czyli ponyfill, który zapewnia funkcjonalność jako samodzielny moduł, którego możesz użyć) o nazwie webtransport-ponyfill-websocket, który implementuje niektóre funkcje WebTransport. Uważnie przeczytaj ograniczenia w README projektu, aby określić, czy to rozwiązanie sprawdzi się w Twoim przypadku.

Kwestie związane z ochroną prywatności i bezpieczeństwem

Aby uzyskać wiarygodne wskazówki, zapoznaj się z odpowiednią sekcją w projektie specyfikacji.

Prześlij opinię

Zespół Chrome chce poznać Twoje opinie i wrażenia związane z korzystaniem z tego interfejsu API.

Opinie na temat projektu interfejsu API

Czy interfejs API jest niewygodny lub nie działa zgodnie z oczekiwaniami? A może brakuje Ci elementów, których potrzebujesz do wdrożenia swojego pomysłu?

Zgłoś problem w repozytorium Web Transport na GitHubie lub podziel się opinią na temat istniejącego problemu.

Problem z implementacją?

Czy znalazłeś/znalazłaś błąd w implementacji Chrome?

Zgłoś błąd na stronie https://new.crbug.com. Podaj jak najwięcej szczegółów i proste instrukcje odtwarzania problemu.

Planujesz korzystać z interfejsu API?

Twoja publiczna pomoc pomaga Chrome ustalać priorytety funkcji i pokazuje innym dostawcom przeglądarek, jak ważna jest ich obsługa.

  • Wyślij tweeta do @ChromiumDev, używając hashtaga #WebTransport i szczegółów dotyczących tego, gdzie i jak go używasz.

Ogólna dyskusja

W przypadku ogólnych pytań lub problemów, które nie pasują do żadnej z pozostałych kategorii, możesz skorzystać z grupy Google web-transport-dev.

Podziękowania

Ten artykuł zawiera informacje z artykułu wyjaśniającego WebTransport, projektu specyfikacjipowiązanych dokumentów projektowych. Dziękujemy autorom za udostępnienie tej podstawy.

Główny obraz w tym poście pochodzi od Robina Pierre z Unsplash.