Utilizzo di WebTransport

WebTransport è un'API che offre messaggistica client-server a bassa latenza, bidirezionale. Scopri di più sui casi d'uso e su come fornire feedback sul futuro dell'implementazione.

Sfondo

Che cos'è WebTransport?

WebTransport è un'API web che utilizza il protocollo HTTP/3 come trasporto bidirezionale. È destinato alle comunicazioni bidirezionali tra un client web e un server HTTP/3. Supporta l'invio di dati sia tramite le sue API datagram sia in modo affidabile tramite le sue API per i flussi.

I datagrammi sono ideali per l'invio e la ricezione di dati che non richiedono forti garanzie di consegna. I singoli pacchetti di dati hanno dimensioni limitate dall'unità massima di trasmissione (MTU) della connessione sottostante e possono essere trasmessi correttamente o meno. Inoltre, se vengono trasferiti, possono arrivare in ordine arbitrario. Queste caratteristiche rendono le API per i datagrammi ideali per la trasmissione dei dati a bassa latenza e con il criterio del "best effort". Puoi pensare ai datagrammi come ai messaggi del protocollo datagramma degli utenti (UDP), ma criptati e controllati dalla congestione.

Le API per i flussi, al contrario, forniscono un trasferimento di dati affidabile e ordinato. Sono adatti agli scenari in cui devi inviare o ricevere uno o più flussi di dati ordinati. L'utilizzo di più flussi WebTransport è analogo alla creazione di più connessioni TCP, ma poiché HTTP/3 utilizza in background il protocollo QUIC, che è più leggero, è possibile aprirli e chiuderli senza lo stesso overhead.

Casi d'uso

Questo è un breve elenco di possibili modi in cui gli sviluppatori potrebbero utilizzare WebTransport.

  • Invio dello stato del gioco a intervalli regolari con latenza minima a un server tramite messaggi di piccole dimensioni, non affidabili e fuori ordine.
  • Ricezione di stream multimediali inviati da un server con latenza minima, indipendentemente da altri stream di dati.
  • Ricezione di notifiche inviate da un server mentre è aperta una pagina web.

Ci interessa saperne di più su come prevedi di utilizzare WebTransport.

Supporto browser

Supporto dei browser

  • Chrome: 97.
  • Edge: 97.
  • Firefox: 114.
  • Safari: non supportato.

Origine

Come per tutte le funzionalità che non dispongono del supporto universale del browser, la programmazione in modo difensivo tramite il rilevamento delle funzionalità è una best practice.

Stato attuale

Passaggio Stato
1. Crea messaggio esplicativo Completato
2. Crea la bozza iniziale delle specifiche Completato
3. Raccogli i feedback e ottimizza la progettazione Completa
4. Prova dell'origine Completa
5. Lancio Chromium 97

Il rapporto di WebTransport con altre tecnologie

WebTransport è un sostituto dei WebSocket?

Forse. In alcuni casi d'uso, è possibile che WebSockets o WebTransport siano protocolli di comunicazione validi da utilizzare.

Le comunicazioni WebSockets sono modellate su un singolo flusso ordinato di messaggi affidabile, che va bene per alcuni tipi di esigenze di comunicazione. Se hai bisogno di queste caratteristiche, le API per i flussi di WebTransport possono fornirle anche. In confronto, le API per i datagrammi di WebTransport forniscono una distribuzione a bassa latenza, senza garanzie di affidabilità o di ordinazione, quindi non sostituiscono direttamente i WebSocket.

L'utilizzo di WebTransport, tramite le API per i datagrammi o tramite più istanze simultanee dell'API Streams, significa che non devi preoccuparti del blocco head-of-line, che può essere un problema dei WebSocket. Inoltre, la creazione di nuove connessioni comporta vantaggi in termini di prestazioni, in quanto il QUIC handshake sottostante è più veloce dell'avvio di TCP su TLS.

WebTransport fa parte di una nuova bozza di specifica e, come tale, l'ecosistema WebSocket dedicato alle librerie client e server è attualmente molto più solido. Se hai bisogno di qualcosa che funzioni "pronto all'uso" con configurazioni di server comuni e con un ampio supporto client web, WebSockets è oggi una scelta migliore.

WebTransport è uguale a un'API UDP Socket?

No. WebTransport non è un'API UDP Socket. Mentre WebTransport utilizza HTTP/3, che a sua volta utilizza UDP "in background", WebTransport ha requisiti per la crittografia e il controllo della congestione che lo rendono molto più di un'API UDP Socket di base.

WebTransport è un'alternativa ai canali di dati WebRTC?

Sì, per le connessioni client-server. WebTransport condivide molte delle proprietà dei canali di dati WebRTC, anche se i protocolli sottostanti sono diversi.

In genere, l'esecuzione di un server compatibile con HTTP/3 richiede meno operazioni di configurazione e configurazione rispetto alla gestione di un server WebRTC, il che comporta la comprensione di più protocolli (ICE, DTLS e SCTP) per garantire un trasporto funzionante. WebRTC include molte altre parti in movimento che potrebbero portare a negoziazioni client/server non riuscite.

L'API WebTransport è stata progettata per i casi d'uso degli sviluppatori web e dovrebbe essere più simile alla scrittura di un codice di una piattaforma web moderna che all'utilizzo delle interfacce dei canali dati di WebRTC. A differenza di WebRTC, WebTransport è supportato all'interno dei web worker, che ti consente di eseguire comunicazioni client-server indipendenti da una determinata pagina HTML. Poiché WebTransport espone un'interfaccia conforme a Streams, supporta le ottimizzazioni intorno alla contropressione.

Tuttavia, se hai già una configurazione client/server WebRTC funzionante che ti soddisfa, il passaggio a WebTransport potrebbe non offrire molti vantaggi.

Prova

Il modo migliore per sperimentare con WebTransport è avviare un server HTTP/3 compatibile. Puoi quindi utilizzare questa pagina con un client JavaScript di base per provare le comunicazioni client/server.

Inoltre, all'indirizzo webtransport.day è disponibile un server echo gestito dalla community.

Utilizzo dell'API

WebTransport è stato progettato sulla base delle moderne piattaforme web primitive, come l'API Streams. Si basa molto sulle promesse e funziona bene con async e await.

L'attuale implementazione di WebTransport in Chromium supporta tre tipi distinti di traffico: datagrammi, nonché stream sia unidirezionali che bidirezionali.

Connessione a un server

Puoi connetterti a un server HTTP/3 creando un'istanza WebTransport. Lo schema dell'URL deve essere https. Devi specificare esplicitamente il numero di porta.

Devi usare la promessa ready di attendere la connessione. Questa promessa non verrà soddisfatta fino al completamento della configurazione e verrà rifiutata se la connessione non riesce nella fase QUIC/TLS.

La promessa closed viene soddisfatta quando la connessione si chiude normalmente e rifiuta se la chiusura è imprevista.

Se il server rifiuta la connessione a causa di un errore di indicazione del client (ad esempio, il percorso dell'URL non è valido), closed viene rifiutato, mentre ready rimane irrisolto.

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;

API Datagram

Una volta che hai un'istanza WebTransport collegata a un server, puoi utilizzarla per inviare e ricevere bit di dati discreti, noti come datagrammi.

Il getter writeable restituisce un oggetto WritableStream, che un client web può utilizzare per inviare dati al server. Il getter readable restituisce un valore ReadableStream, che consente di ascoltare i dati dal server. Entrambi i flussi sono intrinsecamente inaffidabili, quindi è possibile che i dati che scrivi non vengano ricevuti dal server e viceversa.

Entrambi i tipi di stream utilizzano istanze di Uint8Array per il trasferimento di dati.

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

API per i flussi

Una volta stabilita la connessione al server, potresti anche utilizzare WebTransport per inviare e ricevere dati tramite le sue API Streams.

Ogni blocco di tutti gli stream è un Uint8Array. A differenza delle API Datagram, questi flussi sono affidabili. Tuttavia, ogni stream è indipendente, per cui l'ordine dei dati tra i vari stream non è garantito.

WebTransportSendStream

Un WebTransportSendStream viene creato dal client web utilizzando il metodo createUnidirectionalStream() di un'istanza WebTransport, che restituisce una promessa per WebTransportSendStream.

Utilizza il metodo close() di WritableStreamDefaultWriter per chiudere la connessione HTTP/3 associata. Il browser tenta di inviare tutti i dati in attesa prima di chiudere effettivamente la connessione associata.

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

Analogamente, utilizza il metodo abort() di WritableStreamDefaultWriter per inviare un RESET\_STREAM al server. Quando utilizzi abort(), il browser potrebbe eliminare tutti i dati in attesa che non sono ancora stati inviati.

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

Un WebTransportReceiveStream viene avviato dal server. Per ottenere un WebTransportReceiveStream è un processo in due fasi per un client web. Innanzitutto, chiama l'attributo incomingUnidirectionalStreams di un'istanza WebTransport, che restituisce un ReadableStream. Ogni blocco di ReadableStream è, a sua volta, un WebTransportReceiveStream che può essere utilizzato per leggere le istanze Uint8Array inviate dal server.

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

Puoi rilevare la chiusura dello stream utilizzando la promessa closed di ReadableStreamDefaultReader. Quando la connessione HTTP/3 sottostante viene chiusa con il bit FIN, la promessa closed viene soddisfatta dopo la lettura di tutti i dati. Quando la connessione HTTP/3 viene chiusa bruscamente (ad esempio da RESET\_STREAM), la promessa closed viene rifiutata.

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

È possibile che un elemento WebTransportBidirectionalStream venga creato dal server o dal client.

I client web possono crearne uno utilizzando il metodo createBidirectionalStream() di un'istanza WebTransport, che restituisce una promessa per WebTransportBidirectionalStream.

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

Puoi rimanere in ascolto di un evento WebTransportBidirectionalStream creato dal server con l'attributo incomingBidirectionalStreams di un'istanza WebTransport, che restituisce un valore ReadableStream. Ogni blocco di ReadableStream è, a sua volta, un 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
}

Un WebTransportBidirectionalStream è solo una combinazione di WebTransportSendStream e WebTransportReceiveStream. Gli esempi delle due sezioni precedenti spiegano come utilizzarli.

Altri esempi

La specifica di bozza di WebTransport include una serie di esempi in linea aggiuntivi, oltre alla documentazione completa per tutti i metodi e le proprietà.

WebTransport nei DevTools di Chrome

Purtroppo li DevTools di Chrome al momento non supportano WebTransport. Puoi aggiungere a Speciali questo problema di Chrome per ricevere notifiche sugli aggiornamenti dell'interfaccia di DevTools.

Polyfill

Un polyfill (o ponyfill che offre la funzionalità come modulo autonomo utilizzabile) chiamato webtransport-ponyfill-websocket che implementa alcune delle funzionalità di WebTransport. Leggi attentamente i vincoli in README del progetto per determinare se questa soluzione può funzionare per il tuo caso d'uso.

Considerazioni sulla privacy e sulla sicurezza

Per indicazioni autorevoli, consulta la sezione corrispondente della bozza di specifica.

Feedback

Il team di Chrome vuole conoscere le tue opinioni ed esperienze nell'utilizzo di questa API.

Feedback sulla progettazione dell'API

L'API presenta problemi o non funziona come previsto? Oppure mancano delle parti che ti servono per mettere in pratica la tua idea?

Segnala un problema nel repository GitHub di Web Transport o aggiungi le tue opinioni a un problema esistente.

Problemi con l'implementazione?

Hai trovato un bug nell'implementazione di Chrome?

Segnala un bug all'indirizzo https://new.crbug.com. Includi il maggior numero di dettagli possibile, insieme a semplici istruzioni per la riproduzione.

Hai intenzione di utilizzare l'API?

Il supporto pubblico aiuta Chrome a dare la priorità alle funzionalità e mostra agli altri fornitori di browser quanto sia fondamentale supportarle.

Discussione generale

Puoi utilizzare il gruppo Google Web-transport-dev per domande o problemi generali che non rientrano in una delle altre categorie.

Ringraziamenti

Questo articolo include informazioni tratte da WebTransport Explainer, dalle specifiche di bozza e dai documenti di progettazione correlati. Grazie ai rispettivi autori per aver fornito questa fondazione.

L'immagine hero in questo post è di Robin Pierre su Unsplash.