Créer un serveur de notification en Node.js avec Socket.io
Vendredi 10 Mars 2023 08:30

Créer un serveur de notification en Node.js avec Socket.io

Je vous en avais parlé dans mon article sur ma découverte de node.js, la première vraie utilité que j’ai trouvé pour node.js est la mise en place d’un serveur de notification. Il est courant que nos navigateurs envoient des requêtes vers nos serveurs. Par contre pour ce qui est de l’inverse… Un appel ajax toutes les 5 secondes pour vérifier qu’il n’y a pas de notification? Pas très propre… Vraiment pas propre…

C’est là qu’intervient la librairie socket.io qui puise sa force dans la mise en place de websocket permettant la communication bilatérale serveur-navigateur et ca c’est beau !

Pré-requis

Si vous avez besoin d’une piqûre de rappel sur la procédure pour installer et configurer un serveur node.js, je vous invite à consulter mon post justement consacré à la question: Creer son serveur Node.JS

Création et configuration du projet

Je vous la fait en express, commencez par créer un dossier dédié à votre projet (ou réutiliser un dossier existant afin de mutualiser les ressources)

mkdir notifierServer
cd notifierServer

Créer le fichier de config

nano package.json
{
  "name": "notifier-server",
  "version": "0.0.1",
  "description": "Notifier server in nodeJS",
  "dependencies": {}
}

Dépendances

On va se baser une nouvelle fois sur le framework Express

npm install express

Et pour gérer les notifications nous allons donc utiliser Socket.io qui va nous permettre de mettre en place le websocket et la communication qui va avec.

npm install socket.io

Création de notre .js

Tout est pret, il ne nous reste plus qu’à créer notre fichier notifier.js qui contiendra donc la gestion de nos notifications.

nano notifier.js

Une fois créé, on initialise express et socket.io

const express = require('express');
const app = express();
const http = require('http');
const server = http.createServer(app);
const { Server } = require("socket.io");
const io = new Server(server);

On va ensuite rajouter un petit event qui se déclenche lorsqu'un client se connecte juste pour vérifier dans nos logs que la communication existe bien.

io.on('connection', (socket) => {
    console.log('Un client vient de se connecter');
});

Et bien entendu, on ajoute le port à écouter:

server.listen(5001, () => {
    console.log('listening on *:5001');
});

Création d'une page html et insertion du js socket.io

Pour que le serveur ET le navigateur communique entre eux, il faut qu’ils aient les mêmes armes. Dans le fichier index.html qui suit, nous intégrons le code front de socket.io depuis le cdn mais libre à vous de le récupérer sur le github: https://github.com/socketio/socket.io-client

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
      <p>Page de test</p>
      <script src="https://cdn.socket.io/4.5.4/socket.io.min.js" crossorigin="anonymous"></script>
      <script>
          var socket = io('http://127.0.0.1:5001', { transports : ['websocket'] });
      </script>
    </body>
</html>

Premier test

Tout est en place pour établir notre première connection, lançons notre serveur:

node notifier.js

Ouvrons notre index.html dans un navigateur et surveillons notre terminal

Node server

Le navigateur communique bien avec notre serveur.
Bon oui dans ce sens là, ça n'a rien de magique… Mais ici c'est grâce à un websocket ce qui signifie que votre navigateur est à l’écoute !

Ping

Comme je le disais, la communication est ouverte… mais on ne fait rien transiter. On va commencer par ce que l’on connaît: une communication navigateur > serveur mais en utilisant le websocket que l’on vient d’ouvrir.

En ajoutant ceci dans notre index.html

socket.emit("key", "value");

Et ceci du côté du serveur:

io.on("connection", (socket) => {
	//...
	socket.on("key", (arg) => {
		console.log(arg);
	});
	//...
});

Petite précision avant d’aller plus loin: “key” et “value” sont bien évidemment totalement libres.
Vous pouvez bien entendu émettre sur autant de “key” différentes que vous le souhaitez. L’important est qu’il y ait une correspondance sur le serveur.

Pour ce qui est de “value”, il s’agit bien évidemment de la valeur que vous souhaitez transmettre: text, json, ... Pour plus d’info: https://socket.io/fr/docs/v4/emitting-events/

On restart le serveur, on refresh la page…

Gif Simpson - Now we wait

On regarde le terminal

Client vers serveur

Cette fois ça communique dans le sens client -> serveur!

Pong

Je rappelle que nous sommes sur un serveur et un client qui utilisent tous les deux du js et en plus, la même librairie. Ce serait trop bien si en plus les fonctions étaient les mêmes des deux côtés… Mais c’est le cas !
Il suffit donc d'utiliser les mêmes fonctions mais dans l'autre sens...

coté serveur:

io.on("connection", (socket) => {
	//...
	socket.emit("key2", "value2");
	//...
});

coté client:

socket.on("key2", (arg) => {
	console.log(arg);
});

Une fois n'est pas coutume, on restart, on refresh et on regarde le résultat dans la console de notre navigateur

Serveur vers client

Parfait ça communique dans les deux sens !

Notification à la demande

Bon revenons en au but initial: Envoyer depuis notre serveur php une notification au client via notre serveur nodejs

nous savons ajouter une route sur notre serveur mais il faut que cette route puisse accéder aux connexions. Pour ce faire nous allons rendre notre "io" accessible depuis les différentes route en l'ajoutant dans l'app.

app.use(function(req, res, next) {
    req.io = io;
    next();
});

Maintenant que nous pouvons accéder a la constante "io", il nous reste à créer la route /notify qui s'occupera de contacter les clients lors de son appel.

app.get('/notify', (req, res) => {
    var io = req.io;
    io.emit(key2, 'Notify on query');

    res.setHeader('Content-Type', 'application/json');
    res.end(JSON.stringify({ status: "OK" }));
});

On pensera à ajouter un point de sortie, ici un petit json qui confirme que tout c'est bien passé.

Vous connaissez la chanson: restart et refresh.

Gif Visiteur - Jour nuit

Ouvront un nouvelle fenetre et accédons à http://127.0.0.1:5001/notify

Vérifions la console (F12) dans le navigateur sur le fichier index.html

On query

Nous avons donc désormais une url, que nous pouvons appeler depuis notre code php, qui est récupérée par notre script node.js et qui envoie un message à tous les clients connectés !

Je pense que maintenant vous avez toutes les clés en mains pour adapter cette mécanique selon vos besoins. Il y a bien entendu des améliorations à faire comme utiliser une requête post, sécuriser les valeurs transférées, créer le code côté client qui agit correctement en fonction de l’information reçue,... les possibilités sont infinies !

Ha oui, vous pouvez récupérer le code complet ici: https://github.com/kevinrolinbe/nodejs_notifier