• 10 heures
  • Difficile

Ce cours est visible gratuitement en ligne.

Ce cours existe en livre papier.

Vous pouvez obtenir un certificat de réussite à l'issue de ce cours.

Vous pouvez être accompagné et mentoré par un professeur particulier par visioconférence sur ce cours.

J'ai tout compris !

TP : le super Chat

Connectez-vous ou inscrivez-vous gratuitement pour bénéficier de toutes les fonctionnalités de ce cours !

Alors, socket.io vous plaît ?! Une fois qu'on a réussi à le prendre en main, ce qui n'est pas vraiment compliqué quand on commence à avoir l'habitude de Node.js, il faut avouer qu'un grand nombre de possibilités s'offre tout d'un coup à nous ! Imaginez tout ce que vous pouvez commencer à faire en temps réel ! Un Chat, des jeux, des outils collaboratifs pour le travail...

Parmi l'ensemble de ces possibilités, je pense que le Chat est de loin l'application la plus simple à réaliser tout en restant utile et efficace pour impressionner vos proches. 13
J'avoue que la plupart des tutoriels sur socket.io vous proposent de faire un Chat... mais attendez, je parie qu'aucun d'eux ne vous propose de faire un "Super Chat" ! (euh, si vous cherchez la différence... il n'y en a pas, mais je trouve que le nom est cool)

Voilà ce que je vous demande de réaliser :

Le Super Chat que vous allez devoir réaliser
Le Super Chat que vous allez devoir réaliser

Ici j'ai volontairement ouvert 2 fenêtres. Celle de gauche est connectée sous le pseudo "mateo21" et celle de droite sous le pseudo "gérard".

  • Je demande le pseudo avec une boîte de dialogue lors de la connexion.

  • J'affiche le pseudo de celui qui vient de se connecter à tout le monde dans le Chat (ex : "gérard a rejoint le Chat !").

  • Lorsqu'on saisit un message, il est immédiatement affiché dans le navigateur sous le formulaire.

Bref, rien de bien compliqué ! Mais même en vous basant sur les codes du chapitre précédent, il vous faudra travailler un petit peu et réfléchir... et c'est exactement le plan diabolique que j'ai en tête : vous faire travailler. :diable:

Besoin d'aide ?

Vous êtes perdus ? Vous ne savez pas par où commencer ?

Allons allons, si vous avez bien suivi le chapitre précédent sur socket.io ça ne devrait pas trop vous poser de problèmes. Mais bon, comme je suis (décidément) trop sympa, je vais vous donner quelques indices pour vous aider à avancer. :p

Un petit rappel tout d'abord sur ce que vous devez réaliser :

Le Super Chat que vous allez devoir réaliser
Le Super Chat que vous allez devoir réaliser

Posons-nous maintenant les bonnes questions. De combien de fichiers va-t-on avoir besoin ? De toute évidence, je dirais trois :

  • Un fichier package.json qui décrit les dépendances de votre projet Node.js

  • Un fichier app.js pour l'application côté serveur en Node.js

  • Un fichier index.html qui contiendra la page web et le code côté client de gestion du Chat

Voici un petit peu d'aide pour réaliser chacun de ces fichiers. Si vous vous sentez à l'aise, honnêtement, essayez sans mon aide, c'est encore mieux. ;)
(et au pire revenez lire cette section si jamais vous coincez)

package.json

A ce stade, vous devriez savoir créer un package.json les yeux fermés. Je ne vais pas vous réexpliquer la syntaxe, si vous avez un trou de mémoire je vous laisse retourner au chapitre correspondant.

Par contre, côté modules externes, de quoi va-t-on avoir besoin ? Voilà ce que je suggère (et que j'utilise dans ma correction) :

  • socket.io : si vous l'aviez oublié, vous êtes impardonnables.

  • express : tant qu'à faire, autant utiliser express.js dès le début. On ne s'en est pas servi dans le chapitre de découverte de socket.io mais il n'est pas très compliqué à utiliser en combinaison de socket.io. La doc de ce dernier vous explique comment l'utiliser en combinaison d'express.js.

  • ent : un tout petit module qui permet de protéger les chaînes de caractères envoyées par les visiteurs pour transformer le HTML en entités. Permet d'éviter que vos visiteurs s'envoient du code JavaScript dans le Chat !

Honnêtement, express.js et ent ne sont pas obligatoires pour faire fonctionner le Chat. On peut très bien faire sans, mais j'ai choisi de les utiliser d'une part pour faciliter la maintenance du code (pour express.js) et d'autre part pour la sécurité (pour ent).

app.js

Elle devra renvoyer une page web lorsqu'on appellera le serveur. A vous donc de renvoyer un fichier "index.html" à vos visiteurs qui se connectent sur votre site.
Avec express.js, la syntaxe est un petit peu différente mais aussi plus courte.

En plus de la page web "classique", votre serveur Node.js devra gérer les évènements de socket.io. A priori je dirais qu'on n'a besoin d'en gérer que deux :

  • nouveau_client (vous l'appelez comme vous voulez) : signale qu'un nouveau client vient de se connecter au Chat. Devrait transmettre son pseudo pour pouvoir informer les clients avec des messages comme "robert a rejoint le Chat !".

  • message : signale qu'un nouveau message a été posté. Votre rôle, en tant que serveur, sera tout simplement de le redistribuer aux autres clients connectés avec un petit broadcast. Tant qu'à faire, vous récupèrerez le pseudo du posteur dans une variable de session.

En fin de compte, le fichier app.js n'est pas très gros ni très compliqué. Plus je le regarde, plus je le trouve même étonnamment court et simple.

index.html

En fait, c'est peut-être le fichier qui demande le plus de travail et qui devrait vous donner (légèrement) du fil à retordre. Vous allez devoir gérer pas mal de code JavaScript côté client.

Commencez par structurer une page HTML5 basique, avec un titre, un formulaire composé d'un champ de texte et d'un bouton, et une <div> ou une <section> qui contiendra les messages du Chat (par défaut, elle sera vide).

A vous ensuite d'écrire le code JavaScript du client. Personnellement je l'ai placé en bas de la page (pour des raisons de performances c'est une habitude à prendre). J'aurais aussi pu le mettre dans un fichier .js externe, mais je ne l'ai pas fait ici en l'occurrence.

Ce code devra :

  • Se connecter à socket.io

  • Demander le pseudo au visiteur lors du chargement de la page (via un prompt() en JS, c'est le plus simple que j'aie trouvé) et envoyer un signal "nouveau_client".

  • Gérer la réception de signaux de type "nouveau_client" envoyés par le serveur. Cela signifie qu'un nouveau client vient de se connecter. Affichez son nom dans un message, comme par exemple "robert a rejoint le Chat !".

  • Gérer la réception de signaux de type "message" envoyés par le serveur. Cela signifie qu'un autre client vient d'envoyer un message sur le Chat et donc qu'il vous faut l'afficher dans la page.

  • Gérer l'envoi du formulaire, lorsque le client veut envoyer un message aux autres personnes connectées. Il vous faudra récupérer le message saisi dans le formulaire en JavaScript, émettre un signal de type "message" au serveur pour qu'il le distribue aux autres clients, et aussi insérer ce message dans votre propre page. Eh oui, n'oubliez pas que le broadcast du serveur envoie un message à toutes les autres personnes connectées mais pas à vous-mêmes... il faut donc mettre à jour votre propre zone de Chat.

Bon, je vous ai tellement prémâché le travail que j'en ai limite un coup de blues... Si vous n'y arrivez pas avec tout ça... essayez plus fort ! :D

Correction

Rien ne va plus, c'est l'heure de la correction !

Alors, comment s'est passée la réalisation du Super Chat pour vous ? Vous ne devriez pas avoir rencontré trop de problèmes, ce TP était une façon de reformuler un peu plus proprement le chapitre précédent d'introduction à socket.io.

Mon projet est constitué de 3 fichiers :

  • package.json : la description du projet avec la liste de ses dépendances. Tout projet Node.js qui se respecte en a un !

  • app.js : l'application Node.js côté serveur qui gère les interactions avec les différents clients.

  • index.html : la page web envoyée au client qui contient du code JavaScript pour gérer le Chat côté client.

package.json

Notre package.json est très simple :

{
    "name": "super-chat",
    "version": "0.1.0",
    "dependencies": {
        "express": "~3.3.4",
        "socket.io": "~1.2.1",
        "ent": "~0.1.0"
    },
    "author": "Mateo21 <mateo21@email.com>",
    "description": "Un super Chat temps réel avec socket.io"
}

Comme je vous le disais (pour ceux qui ont lu mes astuces d'aide juste avant), j'utilise évidemment socket.io, mais aussi express.js (bien que ce ne soit pas obligatoire) et ent (pour faire appel à une fonction équivalente à htmlentities() de PHP, afin de sécuriser les échanges et d'éviter que les clients ne s'envoient des codes JavaScript malicieux).

app.js

Relativement court, le code serveur du Super Chat n'était pas le fichier le plus difficile à écrire de ce TP !

var app = require('express')(),
    server = require('http').createServer(app),
    io = require('socket.io').listen(server),
    ent = require('ent'), // Permet de bloquer les caractères HTML (sécurité équivalente à htmlentities en PHP)
    fs = require('fs');

// Chargement de la page index.html
app.get('/', function (req, res) {
  res.sendfile(__dirname + '/index.html');
});

io.sockets.on('connection', function (socket, pseudo) {
    // Dès qu'on nous donne un pseudo, on le stocke en variable de session et on informe les autres personnes
    socket.on('nouveau_client', function(pseudo) {
        pseudo = ent.encode(pseudo);
        socket.pseudo = pseudo;
        socket.broadcast.emit('nouveau_client', pseudo);
    });

    // Dès qu'on reçoit un message, on récupère le pseudo de son auteur et on le transmet aux autres personnes
    socket.on('message', function (message) {
        message = ent.encode(message);
        socket.broadcast.emit('message', {pseudo: socket.pseudo, message: message});
    }); 
});

server.listen(8080);

Le début du fichier ne contient rien d'extraordinaire : quelques appels à des modules, la gestion de l'index ("/") où on renvoie index.html... Non vraiment, plus simple, tu meurs. ;)

En-dessous, on a toute la gestion des messages temps réel avec socket.io. En fait, on ne gère que deux types de messages différents :

  • nouveau_client : envoyé par un nouveau client qui vient de charger la page. Il contient son pseudo en paramètre. J'ai choisi de l'encoder (avec ent.encode()) par sécurité. Ainsi, si le visiteur met du JavaScript dans son pseudo, on est paré ! Ensuite je n'ai plus qu'à "sauvegarder" ce pseudo dans une variable de session.

  • message : envoyé par un client qui veut transmettre un message aux autres personnes connectées. On encode d'abord le message (par sécurité, pour retirer le JavaScript malicieux notamment) et on le broadcast avec le pseudo issu de la variable de session. Pour envoyer plusieurs données dans un seul paramètre, je les encapsule dans un objet JavaScript, d'où le code {pseudo: socket.pseudo, message: message}

C'est tout ce que le serveur a besoin de faire ! :D

index.html

OK, le code du client est un poil plus compliqué. Mais alors juste un poil honnêtement.

Le voici tout de go, on le commente juste après, promis :

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8" />
        <title>Super Chat temps réel !</title>
        <style>
            #zone_chat strong {
                color: white;
                background-color: black;
                padding: 2px;
            }
        </style>
    </head>
 
    <body>
        <h1>Le super Chat temps réel !</h1>

        <form action="/" method="post" id="formulaire_chat">
            <input type="text" name="message" id="message" placeholder="Votre message..." size="50" autofocus />
            <input type="submit" id="envoi_message" value="Envoyer" />
        </form>

        <section id="zone_chat">
            
        </section>


        <script src="http://code.jquery.com/jquery-1.10.1.min.js"></script>
        <script src="/socket.io/socket.io.js"></script>
        <script>

            // Connexion à socket.io
            var socket = io.connect('http://localhost:8080');

            // On demande le pseudo, on l'envoie au serveur et on l'affiche dans le titre
            var pseudo = prompt('Quel est votre pseudo ?');
            socket.emit('nouveau_client', pseudo);
            document.title = pseudo + ' - ' + document.title;

            // Quand on reçoit un message, on l'insère dans la page
            socket.on('message', function(data) {
                insereMessage(data.pseudo, data.message)
            })

            // Quand un nouveau client se connecte, on affiche l'information
            socket.on('nouveau_client', function(pseudo) {
                $('#zone_chat').prepend('<p><em>' + pseudo + ' a rejoint le Chat !</em></p>');
            })

            // Lorsqu'on envoie le formulaire, on transmet le message et on l'affiche sur la page
            $('#formulaire_chat').submit(function () {
                var message = $('#message').val();
                socket.emit('message', message); // Transmet le message aux autres
                insereMessage(pseudo, message); // Affiche le message aussi sur notre page
                $('#message').val('').focus(); // Vide la zone de Chat et remet le focus dessus
                return false; // Permet de bloquer l'envoi "classique" du formulaire
            });
            
            // Ajoute un message dans la page
            function insereMessage(pseudo, message) {
                $('#zone_chat').prepend('<p><strong>' + pseudo + '</strong> ' + message + '</p>');
            }
        </script>
    </body>
</html>

La partie un peu complexe se situe dans le code JavaScript à la fin du fichier. On y trouve tout le nécessaire côté client pour gérer le Chat :

  • La connexion à socket.io

  • La demande de son pseudo au client et l'envoi au serveur via un signal de type "nouveau_client". Petit bonus, je me suis permis d'afficher le pseudo dans le <title> de la page afin qu'il apparaisse dans les onglets de mon navigateur. Vu que pour mes tests j'ouvre plusieurs onglets sur ma machine, ça m'aide à me souvenir qui est qui !

  • La récupération du signal "message" envoyé par le serveur. Dans ce cas, j'insère le message dans la zone #zone_chat de la page. J'ai choisi de créer une fonction pour ça car j'ai aussi besoin de cette fonctionnalité au moment de l'envoi du formulaire.

  • La récupération du signal "nouveau_client" où j'affiche "XXX a rejoint le Chat !".

  • La gestion de l'envoi du formulaire. Peut-être la partie la plus délicate. Il faut récupérer le message saisi par le client, l'envoyer au serveur et l'insérer dans notre page (car le serveur transmet le message à tout le monde... sauf nous !). J'en profite aussi pour vider la zone de texte, remettre le focus dessus... et bloquer l'envoi "classique" du formulaire. Le return false est indispensable si on ne veut pas que la page se recharge suite à l'envoi du formulaire. En fait, return false est équivalent à la fonction de jQuery preventDefault().

  • Enfin, la fonction insereMessage() qui est ma foi très simple. Elle rajoute le message qu'on lui envoie avec le pseudo dans la zone de Chat, au début. La fonction prepend() fait partie de jQuery, je ne l'invente pas. ;)

J'ai choisi d'utiliser jQuery dans mon code pour des raisons pratiques, mais vous pouvez bien entendu faire tout ça en pur JavaScript si vous en avez envie (ou avec une autre bibliothèque).

En fait, le code JavaScript côté client est peut-être le plus gros. La partie Node.js serveur est, comme vous le voyez, très simple : on se connecte, on envoie des signaux, on récupère des signaux... et c'est tout !

Télécharger le projet

Vous avez tout le nécessaire ci-dessus. Vous voulez vraiment un fichier .zip tout prêt ? Ok, alors cliquez sur ce lien :

Télécharger le projet Node.js super-chat.zip

Allez plus loin !

Vous voulez vous entraîner encore plus avec socket.io ? Voici de quoi vous occuper pendant un moment (par ordre approximatif de difficulté croissante) !

  • Affichez un message aux autres personnes lors de la déconnexion d'un client

  • Permettez aux clients de changer leur pseudo en plein milieu d'une session de Chat

  • Et si vous rajoutiez des boutons sur la page pour faire jouer des sons préchargés à distance ? Un bon petit "ding" pour que les autres clients endormis se réveillent ?

  • Essayez de sauvegarder les messages en mémoire sur le serveur pour qu'on retrouve la liste des derniers messages échangés lorsqu'on se connecte ! Vous pouvez sauvegarder les informations juste en mémoire vive comme on a appris à le faire... ou essayer carrément de coupler Node.js à une base de données MySQL, MongoDB, redis...

  • Et si vos clients pouvaient s'envoyer des images en plus du texte ? :)

Et si malgré tout ça vous vous ennuyez encore, reprenez le code du précédent TP pour en faire une "todolist partagée en temps réel entre plusieurs clients" ! L'ajout ou la suppression d'une tâche sera automatiquement répercuté auprès des autres clients !

Exemple de certificat de réussite
Exemple de certificat de réussite