[ Web Proxy ]
URL:
Viewing: https://fr.javascript.info/websocket [Back]  [Original]

WebSocket
FR

Nous souhaitons rendre ce projet open source disponible pour les gens du monde entier.

Aidez-nous traduire le contenu de ce tutoriel dans votre langue!

    Rechercher sur Javascript.info:
    Rechercher dans le tutoriel:
    Light themeDark theme
    DanskEnglishEspaolFranaisIndonesiaItalianoTrkeOzbek
    11 juillet 2023

    WebSocket

    Le protocole WebSocket, dcrit dans la spcification RFC 6455 fournit un moyen dchanger des donnes entre le navigateur et le serveur via une connexion persistante. Les donnes peuvent tre transmises dans les deux sens sous forme de paquets, sans interrompre la connexion et de requtes HTTP supplmentaires.

    WebSocket est particulirement adapt aux services qui ncessitent un change de donnes continu, par exemple jeux en ligne, systmes de trading en temps rel, etc.

    Un exemple simple

    Pour ouvrir une connexion websocket, nous devons crer new WebSocket en utilisant le protocole spcial ws dans lurl :

    let socket = new WebSocket("ws://javascript.info");

    Il existe galement un protocole chiffr wss://. Cest comme HTTPS mais pour les websockets.

    Toujours prfrer wss://

    Le protocole wss:// est non seulement chiffr, mais galement plus fiable.

    Cest parce que les donnes ws:// ne sont pas chiffres, par consquent visibles pour tout intermdiaire. Les anciens serveurs proxy ne connaissent pas WebSocket, ils peuvent voir des en-ttes tranges et abandonner la connexion.

    Dun autre ct, wss:// est WebSocket sur TLS, (comme HTTPS est HTTP sur TLS), la couche de scurit de transport chiffre les donnes lexpditeur et dchiffre au rcepteur. Les paquets de donnes sont donc transmis chiffrs via des proxys. Ils ne peuvent pas voir ce quil y a lintrieur et les laisser passer.

    Une fois le socket cr, nous devons couter les vnements quil contient. Il y a au total 4 vnements :

    • open Connection tablie,
    • message Donne reue,
    • error erreur websocket,
    • close connexion ferme.

    Et si nous souhaitons envoyer quelque chose, alors socket.send(data) fera cela.

    Voici un exemple :

    let socket = new WebSocket("wss://javascript.info/article/websocket/demo/hello");
    
    socket.onopen = function(e) {
      alert("[open] Connection established");
      alert("Sending to server");
      socket.send("My name is John");
    };
    
    socket.onmessage = function(event) {
      alert(`[message] Data received from server: ${event.data}`);
    };
    
    socket.onclose = function(event) {
      if (event.wasClean) {
        alert(`[close] Connection closed cleanly, code=${event.code} reason=${event.reason}`);
      } else {
        // par exemple : processus serveur arrt ou rseau en panne
        // event.code est gnralement 1006 dans ce cas
        alert('[close] Connection died');
      }
    };
    
    socket.onerror = function(error) {
      alert(`[error]`);
    };

    des fins de dmonstration, il y a un petit serveur server.js crit en Node.js, pour lexemple ci-dessus, en cours dexcution. Il rpond par Bonjour du serveur, John, puis attend 5 secondes et ferme la connexion.

    Vous verrez donc les vnements open message close.

    On peut dj parler de WebSocket. Cest assez simple, non ?

    Approfondissont maintenant.

    Ouvrir un websocket

    Lorsque new WebSocket(url) est cr, il se connecte immdiatement.

    Lors de la connexion, le navigateur ( laide des en-ttes) demande au serveur: Prenez-vous en charge Websocket ? Et si le serveur rpond oui, alors la conversation se poursuit dans le protocole WebSocket, qui nest pas du tout HTTP.

    []

    Voici un exemple den-ttes de navigateur pour une demande faite par new WebSocket("wss://javascript.info/chat").

    GET /chat
    Host: javascript.info
    Origin: https://javascript.info
    Connection: Upgrade
    Upgrade: websocket
    Sec-WebSocket-Key: Iv8io/9s+lYFgZWcXczP8Q==
    Sec-WebSocket-Version: 13
    • Origin lorigine de la page client, par exemple https://javascript.info. Les objets WebSocket sont cross-origin par nature. Il ny a pas den-ttes spciaux ou dautres limitations. Les anciens serveurs ne sont pas en mesure de grer WebSocket de toute faon, il ny a donc pas de problme de compatibilit. Mais len-tte Origin est important, car il permet au serveur de dcider de discuter ou non en WebSocket avec ce site Web.
    • Connection: Upgrade indique que le client souhaite modifier le protocole.
    • Upgrade: websocket le protocole demand est websocket.
    • Sec-WebSocket-Key une cl gnre alatoirement par le navigateur pour la scurit.
    • Sec-WebSocket-Version Version du protocole WebSocket, 13 est la version actuelle.
    Le handshake WebSocket ne peut pas tre mul

    Nous ne pouvons pas utiliser XMLHttpRequest ou fetch pour effectuer ce type de requte HTTP, car JavaScript nest pas autoris dfinir ces en-ttes.

    Si le serveur accepte de passer WebSocket, il doit envoyer le code de rponse 101 :

    101 Switching Protocols
    Upgrade: websocket
    Connection: Upgrade
    Sec-WebSocket-Accept: hsBlbuDTkk24srzEOTBUlZAlC2g=

    Ici Sec-WebSocket-Accept est Sec-WebSocket-Key, recod laide dun algorithme spcial. En le voyant, le navigateur comprend que le serveur prend rellement en charge le protocole WebSocket.

    Ensuite, les donnes sont transfres en utilisant le protocole WebSocket, nous verrons bientt sa structure (frames). Et ce nest pas du tout HTTP.

    Extensions et sous-protocoles

    Il peut y avoir des en-ttes supplmentaires Sec-WebSocket-Extensions et Sec-WebSocket-Protocol qui dcrivent les extensions et les sous-protocoles.

    Par exemple :

    • Sec-WebSocket-Extensions: deflate-frame signifie que le navigateur prend en charge la compression des donnes. Une extension est lie au transfert des donnes, cest une fonctionnalit qui tend le protocole WebSocket. Len-tte Sec-WebSocket-Extensions est envoy automatiquement par le navigateur, avec la liste de toutes les extensions quil prend en charge.

    • Sec-WebSocket-Protocol: soap, wamp signifie que nous aimerions transfrer non seulement toutes les donnes, mais les donnes SOAP ou les protocoles WAMP (The WebSocket Application Messaging Protocol). Les sous-protocoles WebSocket sont enregistrs dans le catalogue IANA. Donc, cet en-tte dcrit les formats de donnes que nous allons utiliser.

      Cet en-tte facultatif est dfini laide du deuxime paramtre de new WebSocket. Cest le tableau des sous-protocoles, par exemple si nous souhaitons utiliser SOAP ou WAMP :

      let socket = new WebSocket("wss://javascript.info/chat", ["soap", "wamp"]);

    Le serveur doit rpondre avec une liste de protocoles et dextensions quil accepte dutiliser.

    Par exemple, la requte :

    GET /chat
    Host: javascript.info
    Upgrade: websocket
    Connection: Upgrade
    Origin: https://javascript.info
    Sec-WebSocket-Key: Iv8io/9s+lYFgZWcXczP8Q==
    Sec-WebSocket-Version: 13
    Sec-WebSocket-Extensions: deflate-frame
    Sec-WebSocket-Protocol: soap, wamp

    Rponse :

    101 Switching Protocols
    Upgrade: websocket
    Connection: Upgrade
    Sec-WebSocket-Accept: hsBlbuDTkk24srzEOTBUlZAlC2g=
    Sec-WebSocket-Extensions: deflate-frame
    Sec-WebSocket-Protocol: soap

    Ici, le serveur rpond quil prend en charge lextension deflate-frame, et uniquement SOAP des sous-protocoles demands.

    Transfert de donnes

    La communication WebSocket se compose de frames des fragments de donnes, qui peuvent tre envoys de chaque ct et peuvent tre de plusieurs types :

    • text frames contiennent des donnes textuelles que les parties senvoient mutuellement.
    • binary data frames contiennent des donnes binaires que les parties senvoient mutuellement.
    • ping/pong frames sont utiliss pour vrifier la connexion, envoye par le serveur, le navigateur y rpond automatiquement.
    • il y a aussi la connection close frame et quelques autres frames de service.

    Dans le navigateur, nous travaillons directement uniquement avec du texte ou des frames binaires.

    La mthode WebSocket .send() peut envoyer du texte ou des donnes binaires.

    Un appel socket.send(body) autorise body dans une chane de caractres ou un format binaire, y compris Blob, ArrayBuffer, etc. Aucun paramtre requis : il suffit de lenvoyer dans nimporte quel format.

    Lorsque nous recevons les donnes, le texte vient toujours sous forme de chane de caractres. Et pour les donnes binaires, nous pouvons choisir entre les formats Blob et ArrayBuffer.

    Cela est dfini par la proprit socket.binaryType, cest "blob" par dfaut, donc les donnes binaires viennent en tant quobjets Blob.

    Blob est un objet binaire de haut niveau, il sintgre directement avec <a>, <img> et dautres balises, cest donc un dfaut sain. Mais pour le traitement binaire, pour accder aux octets de donnes individuels, nous pouvons le changer en "arraybuffer" :

    socket.binaryType = "arraybuffer";
    socket.onmessage = (event) => {
      // event.data est soit une chane de caractres (si du texte), soit un arraybuffer (si binaire)
    };

    Limitation de dbit

    Imaginez, notre application gnre beaucoup de donnes envoyer. Mais lutilisateur a une connexion rseau lente, peut-tre sur un Internet mobile, en dehors dune ville.

    Nous pouvons appeler socket.send (data) encore et encore. Mais les donnes seront mises en mmoire tampon (stockes) en mmoire et envoyes uniquement aussi rapidement que la vitesse du rseau le permet.

    La proprit socket.bufferedAmount stocke le nombre doctets qui sont mis en mmoire tampon ce moment, en attente dtre envoys sur le rseau.

    Nous pouvons lexaminer pour voir si le socket est rellement disponible pour la transmission.

    // toutes les 100 ms examine le socket et envoi plus de donnes
    // uniquement si toutes les donnes existantes ont t envoyes
    setInterval(() => {
      if (socket.bufferedAmount == 0) {
        socket.send(moreData());
      }
    }, 100);

    Connexion ferme

    Normalement, lorsquune partie souhaite fermer la connexion (le navigateur et le serveur ont les mmes droits), ils envoient un connection close frame avec un code numrique et une raison textuelle.

    La mthode pour cela est :

    socket.close([code], [reason]);
    • code est un code de fermeture WebSocket spcial (facultatif)
    • reason est une chane de caractres qui dcrit la raison de la fermeture (facultatif)

    Ensuite, lautre partie du gestionnaire dvnements close obtient le code et la raison, par exemple :

    // partie fermante :
    socket.close(1000, "Work complete");
    
    // l'autre partie
    socket.onclose = event => {
      // event.code === 1000
      // event.reason === "Work complete"
      // event.wasClean === true (clean close)
    };

    Valeurs de code les plus courantes :

    • 1000 la closure normale par dfaut (utilise si aucun code nest fourni),
    • 1006 aucun moyen pour utiliser ce code manuellement, indique que la connexion a t perdue (pas de frame de fermeture).

    Il existe dautres codes comme :

    • 1001 la partie sen va, par exemple le serveur sarrte ou un navigateur quitte la page,
    • 1009 le message est trop gros pour tre trait,
    • 1011 erreur inattendue sur le serveur,
    • etc.

    La liste complte se trouve dans le RFC6455, 7.4.1.

    Les codes WebSocket sont un peu comme les codes HTTP, mais diffrents. En particulier, tous les codes infrieurs 1000 sont rservs, il y aura une erreur si nous essayons de dfinir un tel code.

    // en cas de rupture de connexion
    socket.onclose = event => {
      // event.code === 1006
      // event.reason === ""
      // event.wasClean === false (no closing frame)
    };

    tat de connexion

    Pour obtenir ltat de la connexion, il existe en outre la proprit socket.readyState avec des valeurs :

    • 0 CONNECTING: la connexion na pas encore t tablie,
    • 1 OPEN: communicante,
    • 2 CLOSING: la connexion se ferme,
    • 3 CLOSED: la connexion est ferme.

    Exemple de tchat

    Passons en revue un exemple de discussion laide de lAPI WebSocket du navigateur et du module Node.js WebSocket https://github.com/websockets/ws. Nous porterons notre attention principalement sur le ct client, mais le serveur est galement simple.

    HTML: nous avons besoin dun <form> pour envoyer des messages et dun <div> pour les messages entrants :

    <!-- message form -->
    <form name="publish">
      <input type="text" name="message">
      <input type="submit" value="Send">
    </form>
    
    <!-- div with messages -->
    <div id="messages"></div>

    De JavaScript, nous voulons trois choses :

    1. Ouvrir la connexion.
    2. Lors de la soumission du formulaire socket.send(message) pour le message.
    3. Sur le message entrant lajouter div#messages.

    Voici le code :

    let socket = new WebSocket("wss://javascript.info/article/websocket/chat/ws");
    
    // envoyer un message depuis le formulaire
    document.forms.publish.onsubmit = function() {
      let outgoingMessage = this.message.value;
    
      socket.send(outgoingMessage);
      return false;
    };
    
    // message reu - affiche le message dans div#messages
    socket.onmessage = function(event) {
      let message = event.data;
    
      let messageElem = document.createElement('div');
      messageElem.textContent = message;
      document.getElementById('messages').prepend(messageElem);
    }

    Le code ct serveur dpasse un peu notre porte. Ici, nous utiliserons Node.js, mais ce nest pas obligatoire. Dautres plateformes ont galement leurs moyens de travailler avec WebSocket.

    Lalgorithme ct serveur sera :

    1. Crer clients = new Set() un ensemble de sockets.
    2. Pour chaque websocket accept, lajouter lensemble clients.add (socket) et configurer lcouteur dvnements message pour obtenir ses messages.
    3. Lorsquun message est reu : parcourir les clients et lenvoyer tout le monde.
    4. Lorsquune connexion est ferme : clients.delete(socket).
    const ws = new require('ws');
    const wss = new ws.Server({noServer: true});
    
    const clients = new Set();
    
    http.createServer((req, res) => {
      // ici, nous ne grons que les connexions websocket
      // dans un projet rel, nous aurions un autre code ici pour grer les demandes non Websocket
      wss.handleUpgrade(req, req.socket, Buffer.alloc(0), onSocketConnect);
    });
    
    function onSocketConnect(ws) {
      clients.add(ws);
    
      ws.on('message', function(message) {
        message = message.slice(0, 50); // la longueur maximale des messages sera de 50
    
        for(let client of clients) {
          client.send(message);
        }
      });
    
      ws.on('close', function() {
        clients.delete(ws);
      });
    }

    Voici lexemple fonctionnel :

    Vous pouvez galement le tlcharger (bouton en haut droite dans liframe) et lexcuter localement. Noubliez pas dinstaller Node.js et npm install ws avant lexcution.

    Rsum

    WebSocket est un moyen moderne davoir des connexions navigateur-serveur persistantes.

    • WebSockets nont pas de limites cross-origin.
    • Ils sont bien pris en charge dans les navigateurs.
    • Peut envoyer/recevoir des chanes de caractres et des donnes binaires.

    LAPI est simple.

    Les mthodes :

    • socket.send(data),
    • socket.close([code], [reason]).

    Les vnements :

    • open,
    • message,
    • error,
    • close.

    WebSocket ne comprend pas lui seul la reconnexion, lauthentification et de nombreux autres mcanismes de haut niveau. Il existe donc des bibliothques client / serveur pour cela, et il est galement possible dimplmenter ces capacits manuellement.

    Parfois, pour intgrer WebSocket dans un projet existant, les gens excutent le serveur WebSocket en parallle avec le serveur HTTP principal et partagent une seule base de donnes. Les requtes WebSocket utilisent wss://ws.site.com, un sous-domaine qui mne au serveur WebSocket, tandis que https://site.com va au serveur HTTP principal.

    Certes, dautres modes dintgration sont galement possibles.

    Carte du tutoriel

    Commentaires

    lire ceci avant de commenter
    • Si vous avez des amliorations suggrer, merci de soumettre une issue GitHub ou une pull request au lieu de commenter.
    • Si vous ne comprenez pas quelque chose dans l'article, merci de prciser.
    • Pour insrer quelques bouts de code, utilisez la balise <code>, pour plusieurs lignes enveloppez-les avec la balise <pre>, pour plus de 10 lignes - utilisez une sandbox (plnkr, jsbin, codepen)

    Web Proxy Viewer  |  New URL  |  Original Page