Utiliser WebTransport

WebTransport est une API offrant une messagerie client-serveur, bidirectionnelle et à faible latence. Découvrez ses cas d'utilisation et comment envoyer des commentaires sur l'avenir de l'implémentation.

Contexte

Qu'est-ce que WebTransport ?

WebTransport est une API Web qui utilise le protocole HTTP/3 en tant que transport bidirectionnel. Il est destiné aux communications bidirectionnelles entre un client Web et un serveur HTTP/3. Il accepte l'envoi de données de manière non fiable via ses API de datagramme et de manière fiable via ses API de flux.

Les datagrammes sont parfaits pour envoyer et recevoir des données qui ne nécessitent pas de garanties de distribution fortes. Les paquets individuels de données sont limités en taille par l'unité de transmission maximale (MTU) de la connexion sous-jacente. Ils peuvent ou non être transmis avec succès. S'ils sont transférés, ils peuvent arriver dans un ordre arbitraire. Ces caractéristiques font des API de datagrammes idéales pour la transmission de données à faible latence et dans la mesure du possible. Vous pouvez considérer les datagrammes comme des messages UDP (User Datagram Protocol), mais chiffrés et dont l'encombrement est contrôlé.

Les API de flux, en revanche, fournissent un transfert de données fiable et ordonné. Ils sont adaptés aux scénarios dans lesquels vous devez envoyer ou recevoir un ou plusieurs flux de données ordonnées. L'utilisation de plusieurs flux WebTransport équivaut à établir plusieurs connexions TCP, mais comme HTTP/3 utilise en arrière-plan le protocole QUIC, qui est plus léger, ils peuvent être ouverts et fermés sans surcharge.

Cas d'utilisation

Voici une petite liste de façons dont les développeurs peuvent utiliser WebTransport.

  • Envoyer l'état du jeu à un serveur à intervalles réguliers avec une latence minimale via des messages de petite taille, non fiables et dans le désordre
  • Recevoir des flux multimédias envoyés depuis un serveur avec une latence minimale, indépendamment des autres flux de données
  • Recevoir des notifications envoyées par un serveur lorsqu'une page Web est ouverte.

Nous souhaitons en savoir plus sur la manière dont vous prévoyez d'utiliser WebTransport.

Prise en charge des navigateurs

Navigateurs pris en charge

  • 97
  • 97
  • 114
  • x

Source

Comme pour toutes les fonctionnalités qui ne sont pas compatibles avec tous les navigateurs, il est recommandé de coder de manière défensive via la détection de fonctionnalités.

État actuel

Step État
1. Créer une vidéo explicative Fin
2. Créer un brouillon initial de la spécification Fin
3. Recueillir les commentaires et itérer la conception Terminé
4. Phase d'évaluation Terminé
5. Lancement Chromium 97

Relation de WebTransport avec d'autres technologies

WebTransport remplace-t-il WebSockets ?

Peut-être. Dans certains cas, les protocoles de communication WebSockets ou WebTransport peuvent être valides.

Les communications WebSockets sont modélisées autour d'un flux de messages unique, fiable et ordonné, ce qui convient à certains types de besoins de communication. Si vous avez besoin de ces caractéristiques, les API de flux de WebTransport peuvent également les fournir. En comparaison, les API de datagramme de WebTransport offrent une livraison à faible latence, sans garantie de fiabilité ni de commande. Elles ne remplacent donc pas directement WebSockets.

L'utilisation de WebTransport, via les API de datagrammes ou via plusieurs instances d'API Streams simultanées, vous évite d'avoir à vous soucier du blocage en tête de ligne, qui peut poser problème avec WebSockets. De plus, l'établissement de nouvelles connexions présente des avantages en termes de performances, car le handshake QIC sous-jacent est plus rapide que le démarrage de TCP sur TLS.

WebTransport fait partie d'un nouveau projet de spécification. Par conséquent, l'écosystème WebSocket qui s'articule autour des bibliothèques clientes et des serveurs est actuellement beaucoup plus robuste. Si vous avez besoin d'une solution qui fonctionne "prête à l'emploi" avec des configurations de serveur courantes et qui offre une prise en charge étendue du client Web, WebSockets est aujourd'hui le meilleur choix.

WebTransport est-il identique à l'API UDP Socket ?

Non. WebTransport n'est pas une API Socket UDP. Alors que WebTransport utilise HTTP/3, qui à son tour utilise UDP "en arrière-plan", WebTransport a des exigences concernant le chiffrement et le contrôle de l'encombrement qui en font plus qu'une API Socket UDP de base.

WebTransport est-il une alternative aux canaux de données WebRTC ?

Oui, pour les connexions client-serveur. WebTransport partage de nombreuses propriétés identiques aux canaux de données WebRTC, bien que les protocoles sous-jacents soient différents.

En général, l'exécution d'un serveur compatible avec HTTP/3 nécessite moins d'installation et de configuration que la maintenance d'un serveur WebRTC. Cela implique de comprendre plusieurs protocoles (ICE, DTLS et SCTP) afin d'obtenir un transport opérationnel. WebRTC implique de nombreux autres éléments mobiles pouvant entraîner l'échec des négociations client/serveur.

L'API WebTransport a été conçue pour répondre aux cas d'utilisation des développeurs Web et devrait ressembler davantage à l'écriture de code de plate-forme Web moderne qu'à l'utilisation des interfaces de canaux de données WebRTC. Contrairement à WebRTC, WebTransport est compatible avec Web Workers, ce qui vous permet d'effectuer des communications client-serveur indépendamment d'une page HTML donnée. Étant donné que WebTransport expose une interface compatible avec Streams, il accepte les optimisations liées à la contre-pression.

Toutefois, si vous disposez déjà d'une configuration client/serveur WebRTC qui vous convient, le passage à WebTransport risque de ne pas offrir de nombreux avantages.

Essayer

Le meilleur moyen d'expérimenter avec WebTransport est de démarrer un serveur HTTP/3 compatible. Vous pouvez ensuite utiliser cette page avec un client JavaScript de base pour tester la communication client/serveur.

De plus, un serveur d'écho géré par la communauté est disponible sur webtransport.day.

Utiliser l'API

WebTransport a été conçu sur la base des primitives des plates-formes Web modernes, telles que l'API Streams. Elle s'appuie en grande partie sur les promesses et fonctionne bien avec async et await.

L'implémentation actuelle de WebTransport dans Chromium accepte trois types de trafic distincts: les datagrammes, et les flux unidirectionnels et bidirectionnels.

Connexion à un serveur

Vous pouvez vous connecter à un serveur HTTP/3 en créant une instance WebTransport. Le schéma de l'URL doit être https. Vous devez spécifier explicitement le numéro de port.

Vous devez utiliser la promesse ready pour attendre que la connexion soit établie. Cette promesse n'est pas honorée tant que la configuration n'est pas terminée. Elle est rejetée en cas d'échec de la connexion à l'étape QUIC/TLS.

La promesse closed est exécutée lorsque la connexion se ferme normalement et est rejetée si la fermeture est inattendue.

Si le serveur refuse la connexion en raison d'une erreur d'indication du client (par exemple, le chemin de l'URL n'est pas valide), closed rejette alors la connexion, tandis que ready n'est pas résolu.

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

Une fois que vous disposez d'une instance WebTransport connectée à un serveur, vous pouvez l'utiliser pour envoyer et recevoir des bits de données discrets, appelés datagrammes.

Le getter writeable renvoie un WritableStream, qu'un client Web peut utiliser pour envoyer des données au serveur. Le getter readable renvoie un ReadableStream, ce qui vous permet d'écouter les données du serveur. Les deux flux ne sont pas fiables par nature. Il est donc possible que les données que vous écrivez ne soient pas reçues par le serveur, et inversement.

Les deux types de flux utilisent des instances Uint8Array pour le transfert de données.

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

Une fois connecté au serveur, vous pouvez également utiliser WebTransport pour envoyer et recevoir des données via ses API Streams.

Chaque fragment de tous les flux est un Uint8Array. Contrairement aux API Datagram, ces flux sont fiables. Toutefois, chaque flux étant indépendant, l'ordre des données n'est pas garanti entre les flux.

WebTransportSendStream

Un WebTransportSendStream est créé par le client Web à l'aide de la méthode createUnidirectionalStream() d'une instance WebTransport, qui renvoie une promesse pour le WebTransportSendStream.

Utilisez la méthode close() de WritableStreamDefaultWriter pour fermer la connexion HTTP/3 associée. Le navigateur tente d'envoyer toutes les données en attente avant de fermer la connexion associée.

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

De même, utilisez la méthode abort() du WritableStreamDefaultWriter pour envoyer un RESET\_STREAM au serveur. Lorsque vous utilisez abort(), le navigateur peut supprimer les données en attente qui n'ont pas encore été envoyées.

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

Une WebTransportReceiveStream est initiée par le serveur. L'obtention d'un WebTransportReceiveStream est un processus en deux étapes pour un client Web. Tout d'abord, il appelle l'attribut incomingUnidirectionalStreams d'une instance WebTransport, qui renvoie un ReadableStream. Chaque fragment de ce ReadableStream est à son tour un WebTransportReceiveStream qui peut être utilisé pour lire les instances Uint8Array envoyées par le serveur.

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

Vous pouvez détecter la fermeture d'un flux à l'aide de la promesse closed du ReadableStreamDefaultReader. Lorsque la connexion HTTP/3 sous-jacente est fermée avec le bit FIN, la promesse closed est remplie une fois toutes les données lues. Lorsque la connexion HTTP/3 est fermée brusquement (par exemple, par RESET\_STREAM), la promesse closed est rejetée.

// 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 peut être créé par le serveur ou par le client.

Les clients Web peuvent en créer un à l'aide de la méthode createBidirectionalStream() d'une instance WebTransport, qui renvoie une promesse pour une WebTransportBidirectionalStream.

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

Vous pouvez écouter un WebTransportBidirectionalStream créé par le serveur avec l'attribut incomingBidirectionalStreams d'une instance WebTransport, qui renvoie un ReadableStream. Chaque fragment de ce ReadableStream est lui-même 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 est simplement une combinaison de WebTransportSendStream et WebTransportReceiveStream. Les exemples des deux sections précédentes expliquent comment utiliser chacun d'eux.

Autres exemples

Le brouillon de spécification WebTransport comprend un certain nombre d'exemples intégrés supplémentaires, ainsi qu'une documentation complète pour toutes les méthodes et propriétés.

WebTransport dans les outils pour les développeurs Chrome

Malheureusement, les outils pour les développeurs Chrome ne sont actuellement pas compatibles avec WebTransport. Vous pouvez activer le suivi de ce problème Chrome pour être informé des mises à jour dans l'interface des outils de développement.

Polyfill

Un polyfill (ou plutôt ponyfill qui fournit une fonctionnalité en tant que module autonome que vous pouvez utiliser) appelé webtransport-ponyfill-websocket qui implémente certaines des fonctionnalités de WebTransport est disponible. Lisez attentivement les contraintes dans le fichier README du projet pour déterminer si cette solution peut fonctionner pour votre cas d'utilisation.

Points à prendre en compte concernant la confidentialité et la sécurité

Consultez la section correspondante du brouillon de spécification pour obtenir des conseils fiables.

Commentaires

L'équipe Chrome souhaite connaître votre avis et vos expériences sur l'utilisation de cette API.

Commentaires sur la conception de l'API

Y a-t-il un élément de l'API qui est gênant ou ne fonctionne pas comme prévu ? Ou manque-t-il des éléments dont vous avez besoin pour mettre en œuvre votre idée ?

Signalez un problème dans le dépôt GitHub Web Transport ou ajoutez vos commentaires à un problème existant.

Un problème d'implémentation ?

Avez-vous détecté un bug dans l'implémentation de Chrome ?

Signalez le bug à l'adresse https://new.crbug.com. Fournissez autant de détails que possible, ainsi que des instructions simples pour reproduire le bug.

Vous prévoyez d'utiliser l'API ?

Votre assistance publique aide Chrome à hiérarchiser les fonctionnalités et montre aux autres fournisseurs de navigateurs à quel point il est essentiel de les prendre en charge.

Discussion générale

Vous pouvez utiliser le groupe Google "web-transport-dev" pour les questions d'ordre général ou les problèmes qui ne rentrent pas dans l'une des autres catégories.

Remerciements

Cet article comprend des informations tirées du WebTransport Explainer, du brouillon de spécification et des documents de conception associés. Nous remercions les auteurs respectifs pour ces bases.

L'image héros de ce post a été réalisée par Robin Pierre sur Unsplash.