WebTransport è un'API che offre messaggistica client-server bidirezionale a bassa latenza. Scopri di più sui casi d'uso e su come inviare feedback sul futuro dell'implementazione.
Sfondo
Che cos'è WebTransport?
WebTransport è un'API web che utilizza il protocollo HTTP/3 come trasporto bidirezionale. È progettato per le comunicazioni bidirezionali tra un client web e un server HTTP/3. Supporta l'invio di dati in modo non affidabile tramite le sue API datagram e in modo affidabile tramite le sue API stream.
I datagrammi sono ideali per l'invio e la ricezione di dati che non richiedono garanzie di recapito elevate. Le dimensioni dei singoli pacchetti di dati sono limitate dall'unità massima di trasmissione (MTU) della connessione sottostante e possono essere trasmessi o meno correttamente. Se vengono trasferiti, possono arrivare in un ordine arbitrario. Queste caratteristiche rendono le API di datagrammi ideali per la trasmissione di dati best effort a bassa latenza. Puoi considerare i datagrammi come messaggi User Datagram Protocol (UDP), ma criptati e con controllo della congestione.
Le API stream, invece, forniscono un trasferimento di dati affidabile e ordinato. Sono particolarmente adatti a scenari in cui devi inviare o ricevere uno o più stream di dati ordinati. L'utilizzo di più stream WebTransport è analogo all'instaurazione di più connessioni TCP, ma poiché HTTP/3 utilizza il protocollo QUIC più leggero, possono essere aperti e chiusi senza un overhead così elevato.
Casi d'uso
Questo è un breve elenco di possibili modi in cui gli sviluppatori potrebbero utilizzare WebTransport.
- Invio dello stato del gioco a un server a intervalli regolari con latenza minima tramite messaggi piccoli, inaffidabili e fuori sequenza.
- Ricezione di stream multimediali inviati da un server con latenza minima, indipendentemente da altri stream di dati.
- Ricezione di notifiche push da un server quando è aperta una pagina web.
Ci interessa sapere di più su come intendi utilizzare WebTransport.
Supporto browser
Come per tutte le funzionalità che non hanno il supporto universale dei browser, la programmazione difensiva tramite il rilevamento delle funzionalità è una best practice.
Stato attuale
Passaggio | Stato |
---|---|
1. Creare un'animazione esplicativa | Completato |
2. Creare una bozza iniziale della specifica | Completato |
3. Raccogli i feedback e esegui l'iterazione del design | Completa |
4. Prova dell'origine | Completa |
5. Lancio | Chromium 97 |
Relazione di WebTransport con altre tecnologie
WebTransport sostituisce WebSocket?
Forse. Esistono casi d'uso in cui WebSockets o WebTransport potrebbero essere protocolli di comunicazione validi da utilizzare.
Le comunicazioni WebSockets sono modellate su un singolo stream di messaggi ordinato e affidabile, che è adatto per alcuni tipi di esigenze di comunicazione. Se hai bisogno di queste caratteristiche, anche le API di streaming di WebTransport possono fornirle. In confronto, le API di datagrammi di WebTransport forniscono un recapito a bassa latenza, senza garanzie di affidabilità o ordinamento, pertanto non sono una sostituzione diretta di WebSocket.
L'utilizzo di WebTransport, tramite le API datagram o tramite più istanze dell'API Streams in contemporanea, ti consente di non preoccuparti del blocco in testa alla coda, che può essere un problema con WebSocket. Inoltre, sono disponibili vantaggi in termini di prestazioni durante l'instaurazione di nuove connessioni, in quanto l'handshake QUIC sottostante è più veloce dell'avvio di TCP su TLS.
WebTransport fa parte di una nuova bozza di specifica e, pertanto, l'ecosistema WebSocket intorno alle librerie client e server è attualmente molto più solido. Se hai bisogno di qualcosa che funzioni "out of the box" con configurazioni di server comuni e con un'ampia assistenza per i client web, WebSockets è una scelta migliore oggi.
WebTransport è uguale a un'API socket UDP?
No. WebTransport non è un'API socket UDP. Sebbene WebTransport utilizzi HTTP/3, che a sua volta utilizza UDP "sotto il cofano", WebTransport ha requisiti relativi alla crittografia e al controllo della congestione che lo rendono più di un'API di socket UDP di base.
WebTransport è un'alternativa ai canali di dati WebRTC?
Sì, per le connessioni client-server. WebTransport condivide molte delle stesse proprietà dei canali di dati WebRTC, anche se i protocolli di base sono diversi.
In genere, l'esecuzione di un server compatibile con HTTP/3 richiede meno configurazione e manutenzione rispetto a un server WebRTC, che richiede la conoscenza di più protocolli (ICE, DTLS e SCTP) per ottenere un trasporto funzionante. WebRTC comporta molti più elementi in movimento che potrebbero portare a negoziazioni client/server non riuscite.
L'API WebTransport è stata progettata tenendo conto dei casi d'uso degli sviluppatori web e dovrebbe essere più simile alla scrittura di codice della piattaforma web moderna rispetto all'utilizzo delle interfacce dei canali di dati di WebRTC. A differenza di WebRTC, WebTransport è supportato all'interno di Web Workers, il che ti consente di eseguire comunicazioni client-server indipendentemente da una determinata pagina HTML. Poiché WebTransport espone un'interfaccia conforme a Streams, supporta le ottimizzazioni relative alla backpressure.
Tuttavia, se hai già una configurazione client/server WebRTC funzionante e soddisfacente, il passaggio a WebTransport potrebbe non offrire molti vantaggi.
Prova
Il modo migliore per fare esperimenti 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, è disponibile un server echo gestito dalla community all'indirizzo webtransport.day.
Utilizzo dell'API
WebTransport è stato progettato sulla base di primitive della piattaforma web moderna, come l'API Streams. Si basa molto sulle promise e funziona bene con async
e await
.
L'attuale implementazione di WebTransport in Chromium supporta tre tipi distinti di traffico: datagrammi, nonché stream unidirezionali e 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 utilizzare la promessa ready
per attendere che la connessione venga stabilita. Questa promessa non verrà soddisfatta finché la configurazione non sarà completata e verrà rifiutata se la connessione non va a buon fine nella fase QUIC/TLS.
La promessa closed
viene soddisfatta quando la connessione si chiude normalmente e viene rifiutata se la chiusura è imprevista.
Se il server rifiuta la connessione a causa di un errore di indicazione del client (ad es. 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 creata un'istanza WebTransport collegata a un server, puoi utilizzarla per inviare e ricevere bit di dati discreti, noti come datagrams.
Il getter writeable
restituisce un WritableStream
, che un client web può utilizzare per inviare dati al server. Il getter readable
restituisce un ReadableStream
, che ti consente di ascoltare i dati dal server. Entrambi gli stream sono intrinsecamente inaffidabili, pertanto è possibile che i dati scritti non vengano ricevuti dal server e viceversa.
Entrambi i tipi di stream utilizzano istanze Uint8Array
per il trasferimento dei 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 Streams
Una volta connesso al server, puoi anche utilizzare WebTransport per inviare e ricevere dati tramite le sue API Streams.
Ogni chunk di tutti gli stream è un Uint8Array
. A differenza delle API Datagram, questi stream sono affidabili. Tuttavia, ogni stream è indipendente, pertanto l'ordine dei dati tra gli stream non è garantito.
WebTransportSendStream
Un WebTransportSendStream
viene creato dal client web utilizzando il metodo createUnidirectionalStream()
di un'istanza WebTransport
, che restituisce una promessa per il 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 i dati in attesa che non sono stati ancora 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. L'ottenimento di un token WebTransportReceiveStream
è un processo in due passaggi per un client web. Innanzitutto, chiama l'attributo incomingUnidirectionalStreams
di un'istanza WebTransport
, che restituisce un ReadableStream
. Ogni chunk di questo 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
Un WebTransportBidirectionalStream
può essere 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 un WebTransportBidirectionalStream
.
const stream = await transport.createBidirectionalStream();
// stream is a WebTransportBidirectionalStream
// stream.readable is a ReadableStream
// stream.writable is a WritableStream
Puoi ascoltare un WebTransportBidirectionalStream
creato dal server con l'attributo incomingBidirectionalStreams
di un'istanza WebTransport
, che restituisce un ReadableStream
. Ogni frammento 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
è semplicemente una combinazione di WebTransportSendStream
e WebTransportReceiveStream
. Gli esempi delle due sezioni precedenti spiegano come utilizzare ciascuno di questi metodi.
Altri esempi
La bozza della specifica WebTransport include una serie di esempi in linea aggiuntivi, oltre alla documentazione completa di tutti i metodi e le proprietà.
WebTransport in DevTools di Chrome
Purtroppo, al momento Chrome DevTools non supporta WebTransport. Puoi aggiungere questo problema di Chrome ai preferiti per ricevere notifiche sugli aggiornamenti nell'interfaccia di DevTools.
Polyfill
È disponibile un polyfill (o meglio un ponyfill che fornisce funzionalità come modulo autonomo che puoi utilizzare) chiamato
webtransport-ponyfill-websocket
che implementa alcune delle funzionalità di WebTransport. Leggi attentamente i vincoli nel README
del progetto per determinare se questa soluzione può funzionare per il tuo caso d'uso.
Considerazioni su privacy e sicurezza
Per indicazioni autorevoli, consulta la sezione corrispondente della bozza della specifica.
Feedback
Il team di Chrome vuole conoscere la tua opinione e le tue esperienze di utilizzo di questa API.
Feedback sul design dell'API
C'è qualcosa nell'API che non funziona come previsto o che è complicato da usare? Oppure mancano dei pezzi per implementare la tua idea?
Invia un problema nel repo GitHub di Web Transport o aggiungi il tuo parere 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 possibile di dettagli, insieme a semplici istruzioni per la riproduzione.
Hai intenzione di utilizzare l'API?
Il tuo supporto pubblico aiuta Chrome a dare la priorità alle funzionalità e mostra ad altri fornitori di browser quanto sia fondamentale supportarle.
- Invia un tweet all'indirizzo @ChromiumDev utilizzando l'hashtag
#WebTransport
e i dettagli su dove e come lo utilizzi.
Discussione generale
Puoi utilizzare il gruppo Google web-transport-dev per domande generali o problemi che non rientrano in una delle altre categorie.
Ringraziamenti
Questo articolo incorpora le informazioni della spiegazione di WebTransport, della bozza della specifica e dei documenti di progettazione correlati. Grazie ai rispettivi autori per aver fornito questa base.
L'immagine hero di questo post è di Robin Pierre su Unsplash.