Utiliser WebTransport

WebTransport est une API qui propose une messagerie bidirectionnelle à faible latence, côté client et côté serveur. Découvrez ses cas d'utilisation et comment nous faire part de vos commentaires sur l'avenir de l'implémentation.

WebTransport est une API Web qui utilise le protocole HTTP/3 comme transport bidirectionnel. Il est destiné aux communications bidirectionnelles entre un client Web et un serveur HTTP/3. Il permet d'envoyer des données de manière non fiable via ses API de datagrammes et de manière fiable via ses API de flux.

Les datagrammes sont idéaux pour envoyer et recevoir des données qui ne nécessitent pas de garanties de diffusion strictes. La taille des paquets de données individuels est limitée par l'unité de transmission maximale (MTU) de la connexion sous-jacente. Ils peuvent être transmis avec succès ou non, et s'ils sont transférés, ils peuvent arriver dans un ordre arbitraire. Ces caractéristiques rendent les API de datagramme idéales pour la transmission de données à faible latence et au mieux. Vous pouvez considérer les datagrammes comme des messages UDP (User Datagram Protocol), mais chiffrés et contrôlés contre la congestion.

À l'inverse, les API de flux fournissent un transfert de données fiable et ordonné. Elles sont adaptées 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 est semblable à l'établissement de plusieurs connexions TCP, mais comme HTTP/3 utilise le protocole QUIC plus léger en interne, elles peuvent être ouvertes et fermées sans trop de surcharge.

Cas d'utilisation

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

  • Envoi de l'état du jeu à un serveur à intervalles réguliers avec une latence minimale via de petits messages hors séquence, peu fiables.
  • Recevoir des flux multimédias transmis par 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 aimerions en savoir plus sur la façon dont vous prévoyez d'utiliser WebTransport.

Prise en charge des navigateurs

Navigateurs pris en charge

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

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

Étape État
1. Créer un message d'explication Fin
2. Créer une première ébauche de la spécification Fin
3. Recueillir des commentaires et itérer la conception Terminé
4. Essai Origin Terminé
5. Lancement Chromium 97

Relation de WebTransport avec d'autres technologies

WebTransport remplace-t-il WebSockets ?

Peut-être. Dans certains cas d'utilisation, WebSockets ou WebTransport peuvent être des protocoles de communication valides.

Les communications WebSockets sont modélisées autour d'un flux de messages unique, fiable et ordonné, ce qui convient parfaitement à 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 datagrammes de WebTransport offrent une diffusion à faible latence, sans garantie de fiabilité ni d'ordre. Elles ne remplacent donc pas directement les WebSockets.

L'utilisation de WebTransport, via les API de datagramme ou via plusieurs instances d'API Streams simultanées, vous évite d'avoir à vous soucier du blocage en tête de file, qui peut être un problème avec les WebSockets. De plus, l'établissement de nouvelles connexions est plus performant, car le handshake QUIC sous-jacent est plus rapide que le démarrage de TCP sur TLS.

WebTransport fait partie d'une nouvelle ébauche de spécification. Par conséquent, l'écosystème WebSocket autour des bibliothèques client et serveur est actuellement beaucoup plus robuste. Si vous avez besoin d'une solution prête à l'emploi avec des configurations de serveur courantes et une compatibilité étendue avec les clients Web, WebSockets est le meilleur choix.

WebTransport est-il identique à une API de socket UDP ?

Non. WebTransport n'est pas une API Socket UDP. Bien que WebTransport utilise HTTP/3, qui à son tour utilise UDP "sous le capot", WebTransport a des exigences en matière de chiffrement et de contrôle de la congestion qui en font plus qu'une API de socket UDP de base.

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

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

En règle générale, l'exécution d'un serveur compatible avec HTTP/3 nécessite moins de configuration que la maintenance d'un serveur WebRTC, qui implique de comprendre plusieurs protocoles (ICE, DTLS et SCTP) pour obtenir un transport fonctionnel. WebRTC implique de nombreux éléments en mouvement qui peuvent entraîner l'échec des négociations client/serveur.

L'API WebTransport a été conçue en tenant compte des cas d'utilisation des développeurs Web. Elle doit ressembler davantage à l'écriture de code de plate-forme Web moderne qu'à l'utilisation des interfaces de canaux de données de WebRTC. Contrairement à WebRTC, WebTransport est compatible avec les 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 est compatible avec les optimisations liées à la pression arrière.

Toutefois, si vous disposez déjà d'une configuration client/serveur WebRTC fonctionnelle qui vous convient, le passage à WebTransport n'offrira peut-être pas beaucoup d'avantages.

Essayer

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

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

Utilisation de l'API

WebTransport a été conçu sur la base de primitives de plate-forme Web modernes, comme l'API Streams. Il s'appuie fortement sur les promesses et fonctionne bien avec async et await.

L'implémentation actuelle de WebTransport dans Chromium est compatible avec trois types de trafic distincts: les datagrammes, ainsi que les flux unidirectionnels et bidirectionnels.

Se connecter à 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 ne sera remplie que lorsque la configuration sera terminée et sera rejetée si la connexion échoue à l'étape QUIC/TLS.

La promesse closed est remplie 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 client (par exemple, le chemin de l'URL n'est pas valide), closed est alors refusé, tandis que ready reste non 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 distincts, appelés datagrams.

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 sont intrinsèquement non fiables. 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 segment de tous les flux est un Uint8Array. Contrairement aux API Datagram, ces flux sont fiables. Cependant, chaque flux étant indépendant, l'ordre des données entre les flux n'est pas garanti.

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 réellement 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() de WritableStreamDefaultWriter pour envoyer un RESET\_STREAM au serveur. Lorsque vous utilisez abort(), le navigateur peut supprimer toutes 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

Un WebTransportReceiveStream est lancé 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 segment de cet élément ReadableStream est, à son tour, un élément 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 du flux à l'aide de la promesse closed de 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 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 un 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 segment de cet ReadableStream est, à son tour, 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 n'est qu'une combinaison de WebTransportSendStream et de WebTransportReceiveStream. Les exemples des deux sections précédentes expliquent comment utiliser chacune d'elles.

Autres exemples

La spécification WebTransport provisoire 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 de Chrome

Malheureusement, les Outils pour les développeurs de Chrome ne sont pas compatibles avec WebTransport pour le moment. Vous pouvez ajouter une étoile à ce problème Chrome pour recevoir des notifications sur les mises à jour dans l'interface DevTools.

Polyfill

Un polyfill (ou plutôt un ponyfill qui fournit des fonctionnalités 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é

Pour obtenir des conseils officiels, consultez la section correspondante du projet de spécification.

Commentaires

L'équipe Chrome souhaite connaître votre avis et votre expérience avec cette API.

Commentaires sur la conception de l'API

L'API présente-t-elle des difficultés ou ne fonctionne-t-elle pas comme prévu ? Ou manque-t-il des éléments 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.

Problème d'implémentation ?

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

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

Vous prévoyez d'utiliser l'API ?

Votre soutien public 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 ou problèmes généraux qui ne correspondent à aucune des autres catégories.

Remerciements

Cet article intègre des informations provenant de la présentation de WebTransport, de la version préliminaire de la spécification et des documents de conception associés. Merci aux auteurs respectifs de nous avoir fourni cette base.

L'image principale de ce post est de Robin Pierre sur Unsplash.