Korzystanie z WebTransport

WebTransport to interfejs API oferujący krótkie czasy oczekiwania, dwukierunkową komunikację między serwerami. Dowiedz się więcej o przypadkach użycia tej funkcji i o tym, jak przesłać opinię na temat przyszłości implementacji.

Tło

Co to jest WebTransport?

WebTransport to internetowy interfejs API, który wykorzystuje protokół HTTP/3 jako transport dwukierunkowy. Służy do dwukierunkowej komunikacji między klientem internetowym a serwerem HTTP/3. Obsługuje wysyłanie danych zarówno niezawodnie przez interfejsy Datagram API, jak i w niezawodny sposób przez interfejsy API strumieniowania.

Datagramy idealnie nadają się do wysyłania i odbierania danych, które nie wymagają silnych gwarancji dostawy. Pojedyncze pakiety danych są ograniczone przez maksymalną jednostkę przesyłania (MTU) bazowego połączenia. Mogą one nie zostać przesłane, ale mogą też dotrzeć w dowolnej kolejności. Dzięki tym cechom interfejsy Datagram API idealnie nadają się do przesyłania danych z krótkim czasem oczekiwania i z maksymalną wydajnością. Można powiedzieć, że datagramy to komunikaty protokołu datagrama użytkownika (UDP), ale są zaszyfrowane i kontrolowane przez zator.

Z kolei interfejsy API strumieni zapewniają niezawodne, uporządkowane przesyłanie danych. Nadają się one dobrze do wysyłania lub odbierania co najmniej jednego strumienia uporządkowanych danych. Korzystanie z wielu strumieni WebTransport jest analogiczne do tworzenia wielu połączeń TCP, ale ze względu na to, że HTTP/3 wykorzystuje lżejszy protokół QUIC, można je otwierać i zamykać bez dużych nakładów pracy.

Przypadki użycia

To tylko krótka lista możliwych sposobów, w jakie deweloperzy mogą korzystać z WebTransport.

  • Wysyłanie do serwera stanu gry w regularnych odstępach czasu z minimalnym opóźnieniem w postaci małych, nierzetelnych i niewłaściwych komunikatów.
  • Odbiera strumienie multimedialne przekazywane z serwera z minimalnym opóźnieniem, niezależnie od innych strumieni danych.
  • Otrzymywanie powiadomień przekazanych z serwera przy otwartej stronie internetowej.

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

Obsługa przeglądarek

Obsługa przeglądarek

  • Chrome: 97.
  • Krawędź: 97.
  • Firefox: 114.
  • Safari: nieobsługiwane.

Źródło

Podobnie jak w przypadku wszystkich funkcji, które nie są obsługiwane przez uniwersalne przeglądarki, sprawdzoną metodą jest kodowanie defensywne z wykorzystaniem wykrywania cech.

Obecny stan,

Krok Stan
1. Utwórz wyjaśnienie Zakończono
2. Utwórz początkową wersję roboczą specyfikacji Zakończono
3. Zbieraj opinie i ulepszaj projekt Zakończone
4. Wersja próbna origin Zakończone
5. Uruchomienie kampanii Chromium 97

Związek WebTransport z innymi technologiami

Czy WebTransport zastępuje WebSockets?

Być może. W niektórych przypadkach prawidłowymi protokołami komunikacyjnymi mogą być WebSockets lub WebTransport.

Komunikacja przez WebSockets opiera się na pojedynczym, niezawodnym i uporządkowanym strumieniu wiadomości, który sprawdza się w przypadku niektórych rodzajów komunikacji. Jeśli potrzebujesz tych cech, możesz skorzystać z interfejsów API strumieni WebTransport. Dla porównania interfejsy API Datagram firmy WebTransport zapewniają wyświetlanie z małym opóźnieniem, bez gwarancji niezawodności czy kolejności, więc nie zastępują one protokołu WebSockets.

Korzystanie z WebTransport przez interfejsy datagram API lub wiele równoczesnych instancji interfejsu Streams API pozwala wyeliminować problem blokowania części strony, które może być problemem w przypadku technologii WebSockets. Dodatkowo podczas nawiązywania nowych połączeń można zwiększyć wydajność, ponieważ bazowe uzgadnianie połączenia QUIC jest szybsze niż uruchamianie TCP przez TLS.

WebTransport jest częścią nowej specyfikacji roboczej i w związku z tym ekosystem WebSocket oparty na bibliotekach klienta i serwera jest obecnie znacznie bardziej rozbudowany. Jeśli potrzebujesz czegoś, co działa „od razu” z typowymi konfiguracjami serwerów i obsługą klientów internetowych, co sprawia, że rozwiązanie WebSockets jest obecnie lepszym wyborem.

Czy interfejs WebTransport to to samo, co interfejs UDP Socket API?

Nie. WebTransport nie jest interfejsem UDP Socket API. Chociaż WebTransport używa protokołu HTTP/3, który z kolei korzysta z protokołu UDP, Z kolei w WebTransport obowiązują wymagania związane z szyfrowaniem i kontrolą zatorów, które sprawiają, że jest to więcej niż zwykły interfejs UDP Socket API.

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

Tak, w przypadku połączeń klient-serwer. WebTransport ma wiele tych samych usług co kanały danych WebRTC, ale używane przez nich protokoły są różne.

Ogólnie rzecz biorąc, uruchomienie serwera zgodnego z HTTP/3 wymaga mniej konfiguracji niż utrzymywanie serwera WebRTC, które wymaga znajomości wielu protokołów (ICE, DTLS i SCTP) w celu uzyskania działającego transportu. WebRTC obejmuje znacznie więcej ruchomych elementów, które mogą prowadzić do nieudanych negocjacji klient-serwer.

Interfejs WebTransport API został zaprojektowany z myślą o przypadkach użycia dla programistów stron internetowych i powinien pisać jak najsłabszy sposób w nowoczesnym kodzie platformy internetowej niż za pomocą interfejsów kanału danych WebRTC. W przeciwieństwie do WebRTC środowisko WebTransport jest obsługiwane w ramach narzędzi Web Workers, które umożliwiają komunikację klient-serwer niezależnie od danej strony HTML. WebTransport udostępnia interfejs zgodny ze strumieniami, dlatego obsługuje optymalizacje związane z prepresją wsteczną.

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

Wypróbuj

Najlepszym sposobem na eksperymentowanie z funkcją WebTransport jest uruchomienie zgodnego serwera HTTP/3. Następnie możesz użyć tej strony w podstawowym kliencie JavaScript, aby wypróbować komunikację klient-serwer.

Dodatkowo na stronie webtransport.day dostępny jest obsługiwany przez społeczność serwer echa.

Korzystanie z interfejsu API

Usługa WebTransport została zaprojektowana w oparciu o nowoczesne podstawowe elementy platformy internetowej, takie jak Streams API. W dużej mierze polega na obietnicach i dobrze działa z async i await.

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

Łączenie z serwerem

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

Zaczekaj na połączenie z obietnicą ready. Ta obietnica nie zostanie spełniona do czasu ukończenia konfiguracji i zostanie odrzucona, jeśli połączenie nie powiedzie się na etapie QUIC/TLS.

Obietnica closed zostaje zrealizowana, gdy połączenie zamyka się normalnie, i odrzuca, jeśli zamknięcie było nieoczekiwane.

Jeśli serwer odrzuci połączenie z powodu błędu wskaźnika klienta (np. ścieżka adresu URL jest nieprawidłowa), wtedy closed odrzuca połączenie, a ready pozostaje 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.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 API Datagram

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

Metoda pobierania writeable zwraca obiekt WritableStream, którego klient internetowy może użyć do wysłania danych na serwer. Metoda pobierania readable zwraca błąd ReadableStream, co umożliwia nasłuchiwanie danych z serwera. Oba strumienie są z natury zawodne, więc może się zdarzyć, że zapisywane przez Ciebie dane nie zostaną odebrane przez serwer i odwrotnie.

Oba typy strumieni do przenoszenia danych używają instancji Uint8Array.

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

Po połączeniu się z serwerem możesz też używać WebTransport do wysyłania i odbierania danych przez interfejsy 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 we wszystkich strumieniach nie jest gwarantowana.

WebTransportSendStream

Klient internetowy tworzy WebTransportSendStream przy użyciu metody createUnidirectionalStream() instancji WebTransport, która zwraca obietnicę dla WebTransportSendStream.

Aby zamknąć powiązane połączenie HTTP/3, użyj metody close() komponentu WritableStreamDefaultWriter. Przeglądarka próbuje wysłać wszystkie oczekujące dane, zanim faktycznie zamknie powiązane połączenie.

// 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() WritableStreamDefaultWriter, aby wysłać RESET\_STREAM na serwer. Podczas używania funkcji abort() przeglądarka może odrzucić wszelkie 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

Zdarzenie WebTransportReceiveStream jest inicjowane przez serwer. W przypadku klienta internetowego uzyskanie WebTransportReceiveStream to proces dwuetapowy. Najpierw wywołuje atrybut incomingUnidirectionalStreams instancji WebTransport, który zwraca ReadableStream. Każdy fragment tego elementu ReadableStream to z kolei element WebTransportReceiveStream, który może służyć 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);
}

Zamknięcie transmisji możesz wykryć, używając obietnicy closed dotyczącej ReadableStreamDefaultReader. Gdy bazowe połączenie HTTP/3 zostanie zamknięte bitem FIN, obietnica closed zostanie spełniona po odczycie wszystkich danych. W przypadku nagłego zamknięcia połączenia HTTP/3 (np. przez RESET\_STREAM) obietnica closed odrzuca.

// 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ć utworzony przez serwer lub klienta.

Klienty internetowe mogą je utworzyć przy użyciu metody createBidirectionalStream() instancji WebTransport, która zwraca obietnicę 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 przy użyciu atrybutu incomingBidirectionalStreams instancji WebTransport, który zwraca ReadableStream. Każdy fragment tego elementu ReadableStream to 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
}

Element WebTransportBidirectionalStream jest tylko kombinacją elementów WebTransportSendStream i WebTransportReceiveStream. Przykłady z 2 poprzednich sekcji wyjaśniają, jak korzystać z każdej z nich.

Więcej przykładów

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

WebTransport w Narzędziach deweloperskich w Chrome

Narzędzia deweloperskie w Chrome obecnie nie obsługują WebTransport. Możesz oznaczyć gwiazdką tym problemem w Chrome, aby otrzymywać powiadomienia o aktualizacjach interfejsu Narzędzi deweloperskich.

Watolina

Kod polyfill (lub inaczej „ponyfill”, który działa jako osobny moduł) o nazwie webtransport-ponyfill-websocket który obsługuje niektóre funkcje WebTransport. Uważnie przeczytaj ograniczenia README projektu, aby określić, czy to rozwiązanie może się sprawdzić w Twoim przypadku użycia.

Kwestie dotyczące prywatności i bezpieczeństwa

Wiarygodne wskazówki znajdziesz w odpowiedniej sekcji w wersji roboczej specyfikacji.

Prześlij opinię

Zespół Chrome chce poznać Twoje przemyślenia i doświadczenia dotyczące tego interfejsu API.

Opinia na temat projektu interfejsu API

Czy jest coś, co sprawia, że interfejs API działa niezręcznie lub nie działa zgodnie z oczekiwaniami? A może brakuje Ci elementów, których potrzebujesz, aby zrealizować swój pomysł?

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

Problem z implementacją?

Czy wystąpił błąd z implementacją Chrome?

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

Planujesz korzystać z interfejsu API?

Twoje publiczne wsparcie pomaga Chrome traktować priorytetowo funkcje, a inni dostawcy przeglądarek pokazują, jak ważne jest, aby wspierać te funkcje.

  • Wyślij tweeta na adres @ChromiumDev, używając hashtagu #WebTransport. oraz szczegóły na temat tego, gdzie i jak go używasz.

Dyskusja ogólna

Możesz użyć grupy dyskusyjnej Google web-transport-dev, aby zadać ogólne pytania lub problemy, które nie pasują do żadnej z pozostałych kategorii.

Podziękowania

Ten artykuł zawiera informacje z dokumentu WebTransport Explainer, specyfikacji roboczej wersji i powiązanych dokumentów o projektowaniu. Dziękujemy autorom za stworzenie odpowiednich podstaw.

Baner powitalny w tym poście autorstwa Robin Pierre na kanale Unsplash.