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 wiarygodnie 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. Dobrze się sprawdzają w sytuacjach, 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

Browser Support

  • Chrome: 97.
  • Edge: 97.
  • Firefox: 114.
  • Safari: not supported.

Source

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 klienta i serwera jest obecnie znacznie bardziej niezawodny. Jeśli potrzebujesz czegoś, co działa „od razu” z popularnymi konfiguracjami serwera i z obsługą wielu klientów internetowych, lepszym wyborem jest obecnie protokół WebSocket.

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 ich podstawowe protokoły są różne.

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 uzyskania 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, i zostanie odrzucona, jeśli połączenie nie powiedzie się na etapie QUIC/TLS.

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 danymigramami.

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 używają 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ązany strumień HTTP/3, użyj metody close() interfejsu WritableStreamDefaultWriter. Przed zamknięciem powiązanego strumienia 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, korzystając z obietnicy closed w ReadableStreamDefaultReader. Gdy podstawowy strumień HTTP/3 jest zamykany za pomocą bitu FIN, obietnica closed jest spełniana po odczytaniu wszystkich danych. Gdy strumień HTTP/3 zostanie zamknięty nagle (np. przez RESET_STREAM), obietnica closed zostanie odrzucona.

// 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 odsłuchiwać zdarzeń WebTransportBidirectionalStream utworzonych przez serwer za pomocą atrybutu incomingBidirectionalStreams instancji WebTransport, które zwracają wartość 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 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 #WebTransporti szczegółów dotyczących tego, gdzie i jak go używasz.

Ogólna dyskusja

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

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.