Korzystanie z WebTransport

WebTransport to interfejs API, który umożliwia dwukierunkowe przesyłanie wiadomości między klientem a serwerem z niewielkimi opóźnieniami. Dowiedz się więcej o przypadkach użycia i o tym, jak przekazywać opinie na temat przyszłości wdrożenia.

Tło

Co to jest WebTransport?

WebTransport to interfejs API sieci, który używa protokołu HTTP/3 jako transportu dwukierunkowego. Jest on przeznaczony do dwukierunkowej komunikacji między klientem internetowym a serwerem HTTP/3. Umożliwia wysyłanie danych zarówno w sposób zawodny za pomocą interfejsów API datagramów, jak i w sposób niezawodny za pomocą interfejsów API strumieni.

Datagramy idealnie nadają się do wysyłania i odbierania danych, które nie wymagają silnych gwarancji dostawy. Poszczególne pakiety danych mają ograniczony rozmiar, który zależy od maksymalnej jednostki przesyłania (MTU) połączenia bazowego. Mogą one zostać przesłane lub nie, a jeśli zostaną przesłane, mogą dotrzeć w dowolnej kolejności. Dzięki tym cechom interfejsy API datagramów idealnie nadają się do transmisji danych z małym opóźnieniem i najwyższą starannością. Datagramy można traktować jako wiadomości protokołu pakietów użytkownika (UDP), ale zaszyfrowane i z kontrolą przeciążenia.

Interfejsy API strumieni zapewniają natomiast niezawodne przesyłanie danych w określonej kolejności. Dobrze sprawdzają się w sytuacjach, w których musisz 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 dużego narzutu.

Przypadki użycia

To tylko niewielka lista możliwych sposobów wykorzystania WebTransportu przez programistów.

  • Wysyłanie stanu gry w regularnych odstępach czasu z minimalnym opóźnieniem na serwer za pomocą małych, niewiarygodnych 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 z serwera, gdy strona jest otwarta;

Chętnie dowiemy się więcej o tym, jak planujesz korzystać z WebTransportu.

Obsługa przeglądarek

Browser Support

  • Chrome: 97.
  • Edge: 97.
  • Firefox: 114.
  • Safari: behind a flag.

Source

Podobnie jak w przypadku wszystkich funkcji, które nie są obsługiwane przez wszystkie przeglądarki, najlepszym rozwiązaniem jest defensywne kodowanie za pomocą wykrywania funkcji.

Obecny stan,

Krok Stan
1. Tworzenie wyjaśnienia Zakończono
2. Tworzenie wstępnej wersji specyfikacji Zakończono
3. Zbieranie opinii i ulepszanie projektu Zakończone
4. Wersja próbna origin Zakończone
5. Uruchom Chromium 97

Związek WebTransport z innymi technologiami

Czy WebTransport zastępuje WebSockets?

Być może. W niektórych przypadkach użycia protokoły WebSockets i WebTransport mogą być odpowiednimi protokołami komunikacji.

Komunikacja za pomocą protokołu WebSocket opiera się na jednym, niezawodnym i uporządkowanym strumieniu wiadomości, co w przypadku niektórych rodzajów komunikacji jest wystarczające. Jeśli potrzebujesz tych cech, interfejsy API strumieni WebTransport też mogą je zapewnić. Dla porównania interfejsy API datagramów WebTransport zapewniają dostarczanie danych z niskim opóźnieniem, ale bez gwarancji niezawodności i kolejności, więc nie są bezpośrednim zamiennikiem WebSocket.

Korzystanie z WebTransportu za pomocą interfejsów API datagramów lub wielu równoczesnych instancji interfejsu Streams API oznacza, że nie musisz się martwić blokowaniem na początku kolejki, które może być problemem w przypadku WebSocketów. Nawiązywanie nowych połączeń jest też bardziej wydajne, ponieważ uzgadnianie połączenia QUIC jest szybsze niż uruchamianie protokołu TCP przez TLS.

WebTransport jest częścią nowego projektu specyfikacji, dlatego ekosystem WebSocket obejmujący biblioteki klienta i serwera jest obecnie znacznie bardziej rozbudowany. Jeśli potrzebujesz rozwiązania, które działa „od razu po wyjęciu z pudełka” w przypadku typowych konfiguracji serwera i jest szeroko obsługiwane przez klientów internetowych, lepszym wyborem będą protokoły WebSocket.

Czy WebTransport to to samo co interfejs API gniazda UDP?

Nie. WebTransport nie jest interfejsem UDP Socket API. WebTransport używa protokołu HTTP/3, który z kolei korzysta z protokołu UDP, ale WebTransport ma wymagania dotyczące szyfrowania i kontroli przeciążenia, które sprawiają, że jest czymś więcej niż podstawowym interfejsem 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 jak kanały danych WebRTC, chociaż protokoły bazowe są inne.

Ogólnie rzecz biorąc, uruchomienie serwera zgodnego z HTTP/3 wymaga mniej konfiguracji niż utrzymywanie serwera WebRTC, co wiąże się ze znajomością wielu protokołów (ICE, DTLSSCTP), aby uzyskać działający transport. WebRTC obejmuje znacznie więcej elementów, które mogą prowadzić do nieudanych negocjacji między klientem a serwerem.

Interfejs WebTransport API został zaprojektowany z myślą o przypadkach użycia przez programistów internetowych i powinien przypominać pisanie nowoczesnego kodu platformy internetowej bardziej niż korzystanie z interfejsów kanału danych WebRTC. W przeciwieństwie do WebRTC WebTransport jest obsługiwany w Web Workers, co umożliwia komunikację między klientem a serwerem niezależnie od danej strony HTML. WebTransport udostępnia interfejs zgodny ze standardem Streams, dlatego obsługuje optymalizacje związane z ograniczaniem przepustowości.

Jeśli jednak masz już działającą konfigurację klienta/serwera WebRTC, z której jesteś zadowolony, 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 wypróbować komunikację między klientem a serwerem.

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

Korzystanie z interfejsu API

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

Obecna implementacja WebTransport w Chromium obsługuje 3 rodzaje ruchu: datagramy oraz strumienie jednokierunkowe i dwukierunkowe.

Nawiązywanie połączenia z serwerem

Możesz połączyć się z serwerem HTTP/3, tworząc instancję WebTransport. Schemat adresu URL powinien mieć postać https. Musisz wyraźnie określić numer portu.

Aby poczekać na nawiązanie połączenia, użyj obietnicy ready. 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 zostanie zamknięte w normalny sposób, a odrzucana, gdy zamknięcie było nieoczekiwane.

Jeśli serwer odrzuci połączenie z powodu błędu wskazania klienta (np. ścieżka adresu URL jest nieprawidłowa), spowoduje to odrzucenie przez closed, a ready pozostanie nierozwiązany.

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.t>hen(() = {
  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 API datagramów

Gdy masz instancję WebTransport połączoną z serwerem, możesz jej używać do wysyłania i odbierania dyskretnych fragmentów danych, czyli datagramów.

Getter writeable zwraca obiekt WritableStream, którego klient internetowy może użyć do wysyłania danych na serwer. Funkcja pobierająca readable zwraca obiekt ReadableStream, który umożliwia nasłuchiwanie danych z serwera. Oba strumienie są z natury zawodne, więc istnieje możliwość, że zapisane przez Ciebie dane nie zostaną odebrane przez serwer i odwrotnie.

Oba typy strumieni używają instancji Uint8Array do przesyłania 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 API Streams.

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 strumieniach nie jest gwarantowana.

WebTransportSendStream

Obiekt WebTransportSendStream jest tworzony przez klienta internetowego za pomocą metody createUnidirectionalStream() instancji WebTransport, która zwraca obietnicę dotyczącą obiektu WebTransportSendStream.

Użyj metody close() interfejsu WritableStreamDefaultWriter, aby zamknąć powiązany strumień HTTP/3. Przeglądarka próbuje wysłać wszystkie oczekujące dane, zanim zamknie powiązany strumień.

// 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() interfejsu WritableStreamDefaultWriter, aby wysłać do serwera RESET_STREAM. Gdy używasz 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. Uzyskanie WebTransportReceiveStream to w przypadku klienta internetowego proces dwuetapowy. Najpierw wywołuje atrybut incomingUnidirectionalStreams instancji WebTransport, który zwraca ReadableStream. Każdy fragment tego ReadableStream jest z kolei WebTransportReceiveStream, którego można użyć do odczytywania instancji Uint8Array wysył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);
}

Zamknięcie strumienia możesz wykryć za pomocą obietnicy closed interfejsu ReadableStreamDefaultReader. Gdy podstawowy strumień HTTP/3 zostanie zamknięty za pomocą bitu FIN, obietnica closed zostanie spełniona po odczytaniu wszystkich danych. Gdy strumień HTTP/3 zostanie nagle zamknięty (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.');
}).ca>tch(() = {
  console.error('The receiveStream closed abruptly.');
});

WebTransportBidirectionalStream

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

Klienci internetowi mogą utworzyć taki obiekt za pomocą metody createBidirectionalStream() instancji WebTransport, która zwraca obietnicę dotyczącą obiektu WebTransportBidirectionalStream.

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

Możesz nasłuchiwać zdarzenia WebTransportBidirectionalStream utworzonego przez serwer za pomocą atrybutu incomingBidirectionalStreams instancji WebTransport, który zwraca wartość ReadableStream. Każda część tego elementu ReadableStream jest z kolei elementem 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 po prostu połączenie WebTransportSendStreamWebTransportReceiveStream. Przykłady z dwóch poprzednich sekcji pokazują, jak używać każdej z nich.

Więcej przykładów

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

WebTransport w Narzędziach deweloperskich w Chrome

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

Watolina poliestrowa

Dostępny jest polyfill (a raczej ponyfill, który udostępnia funkcje jako samodzielny moduł, z którego możesz korzystać) o nazwie webtransport-ponyfill-websocket implementujący niektóre funkcje WebTransport. Uważnie przeczytaj ograniczenia w README projektu, aby sprawdzić, czy to rozwiązanie sprawdzi się w Twoim przypadku.

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

Więcej informacji znajdziesz w odpowiedniej sekcji projektu specyfikacji.

Prześlij opinię

Zespół Chrome chce poznać Twoje opinie i doświadczenia związane z korzystaniem z tego interfejsu API.

Opinie o projekcie interfejsu API

Czy w interfejsie API jest coś, co jest niewygodne lub nie działa zgodnie z oczekiwaniami? A może brakuje Ci elementów, które są niezbędne do realizacji Twojego pomysłu?

Zgłoś problem w repozytorium GitHub Web Transport lub dodaj swoje uwagi do istniejącego zgłoszenia.

Masz problem z implementacją?

Czy w implementacji Chrome występuje błąd?

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

Planujesz korzystać z interfejsu API?

Twoje publiczne wsparcie pomaga zespołowi Chrome ustalać priorytety funkcji i pokazuje innym dostawcom przeglądarek, jak ważne jest ich obsługiwanie.

  • Wyślij tweeta do @ChromiumDev z hasztagiem #WebTransport i szczegółami dotyczącymi tego, gdzie i jak korzystasz z tej funkcji.

Dyskusja ogólna

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

Podziękowania

Ten artykuł zawiera informacje z wyjaśnienia WebTransport, projektu specyfikacjipowiązanych dokumentów projektowych. Dziękujemy autorom za stworzenie podstaw.

Baner powitalny w tym poście jest autorstwa Robina Pierre’a z Unsplash.