Il y a quelque temps je vous avais laissé avec une introduction ultra basique de node.js avec l'application qui ne servait à rien si ce n'est à poser quelques bases. Voici la suite.
Dans cet exemple, le but sera de faire un chat basique en Ajax. On va modifier les sources du post précédent pour arriver à nos fins.
Nous avons vu que la base utilisait les templates ejs (pour un cours de rattrapage, c'est par ici, c'est en anglais, mais c'est simple ).
Mise en place d’un écran de login basique
Pour un chat, la première chose à faire est s'identifier. On va donc créer un template d'identification tout simple. Celui-ci n'a strictement aucun intérêt, mais c'est plus propre ainsi.
On va donc l'enregistrer dans /views/login.ejs
Il est simplement constitué d'un champ de saisi Username et d'un bouton.
<!DOCTYPE html> <html> <head> <title><%= title %></title> <link rel='stylesheet' href='/stylesheets/style.css' /> </head> <body> <form method="post" action="/login"> <h1>Identification Username</h1> <input name="username" autofocus> <button>OK</button> </form> </body> </html>
On va également modifier la route de base pour passer par le login.
Dans /routes/index.js on modifie la route de base de la façon suivante
exports.index = function(req, res){
res.render('login', { title: 'Login' });
};
TEST1
Lancez le test depuis le répertoires “messages” avec la commande suivante:
supervisor app.js
Allez dans votre navigateur et entrez http://localhost:3000
Si vous avez l’idée d’entrer un prénom et de valider vous allez obtenir une erreur. Ce qui est normal vu que nous n’avons pas géré la route /login !!!
Vous l’aurez compris cet exemple n’a guère plus d’intérêt que la création de la base node.js.
Petite amélioration de App.js et templates index.ejs
On va ajouter quelques routes, des variables globales (on sait en php faut jamais, jamais faire ça, ça tombe bien on est pas en php).
Modification du App.js - v2
En haut du app.js on ajoute deux variables globales
var Messages = []; // stockage des messages
var Username = ""; // stokage du Username
Ensuite on ajoute 2 routes et un peu de traitements pour ajouter les messages dans le tableau global Messages et la variable Username.
/* Ajout de la route pour login */ app.post('/login',function(req,res) { Username = req.body.username; res.render('index', { title : Username, Username:'',sessionID : req.sessionID, Messages:'' }); }); /* Ajout de la route et le traitement des messages */ app.post('/envoyer', function(req,res) { if (Username !== "" && Username !== undefined) { Messages.push({Username:Username,Texte:req.body.message}); // on dépaque les messages à l'ancienne var val=""; for (var i=0 in Messages) { val += "<li>"+Messages[i].Username + ':' + Messages[i].Texte+"</li>"; } // On envoi les messages vers la page index res.render('index',{ title : 'Messages', Username: Username,sessionID : req.sessionID,Messages : val }); } // SI on est pas connecté on envoi vers la page de connexion else { res.redirect('/'); } });
Modification du template index.ejs - v2
Ici pas grand chose à faire, juste ajouter un formulaire avec un champ de saisie “message”
<!DOCTYPE html> <html> <head> <title><%= title %></title> <link rel='stylesheet' href='/stylesheets/style.css' /> </head> <body> <h1><%= title %></h1> <p>Welcome to <%= title %> <%= Username %></p> <form id="message" action="envoyer" method="post"> <label for="message" >Entrez un message></label> <input type="text" id="message" name="message"/> <button id="buttonsend"> Envoyer </button> <ul id="messages"> <%- Messages %> </ul> </form> </body> </html>
TEST 2
On lance app.js avec Supervisor si vous l’avez stoppé (ctrl + C)
Sinon Supervisor a du normalement redémarrer app.js. Si pas d’erreur (ce n’est pas lesieur) on doit avoir un truc du style
DEBUG: crashing child
DEBUG: Starting child process with 'node app.js'
Express server listening on port 3000
Ce chat ne sert toujours à rien, il faut envoyer un message pour voir les messages des autres !!! et F5 est inhibé.
Vous pouvez télécharger l’exemple en cliquant ICI (v2)
Version avec un peu d’ajax
Pour cette dernière version ultra simple et sans optimisation on va ajouter de l’ajax histoire de ne pas rafraîchir la page mais uniquement les messages.
Modification du template index.ejs - v3
On va transformer un petit peu le template (3 fois rien), un petit bout de javascript. Attention cet exemple ne doit pas fonctionner sous IE (on peut aussi jouer avec Jquery pour simplifier la chose).
On va retirer les balises form et on va ajouter l’ajax
<script type="text/javascript"> (function() { var httpRequest; document.getElementById("buttonsend").onclick = function() { makeRequest('/envoyer'); }; function makeRequest(url) { if (window.XMLHttpRequest) { // Mozilla, Safari, ... httpRequest = new XMLHttpRequest(); } else if (window.ActiveXObject) { // IE try { httpRequest = new ActiveXObject("Msxml2.XMLHTTP"); } catch (e) { try { httpRequest = new ActiveXObject("Microsoft.XMLHTTP"); } catch (e) {} } } if (!httpRequest) { alert('Giving up :( Cannot create an XMLHTTP instance'); return false; } httpRequest.onreadystatechange = modifListMsg; httpRequest.open('POST', url); httpRequest.setRequestHeader("Content-type","application/x-www-form-urlencoded"); httpRequest.send("message="+document.getElementById("message").value); } //on envoi le message function modifListMsg() { if (httpRequest.readyState === 4) { if (httpRequest.status === 200) { document.getElementById("messages").innerHTML = httpRequest.responseText; } else { alert('There was a problem with the request.'); } }
Modification du App.js - v3
Dans App.js, on va ajouter une fonction pour récupérer uniquement le tableau de messages. Cette fonction sera appelé en ajax toutes les 3 secondes
On va modifier la fonction de d’ajout dans le tableau en ajoutant un contrôle pour éviter les messages vides.
On va également ajouter une route pour récupérer uniquement le tableau de messages.
app.post('/envoyer', function(req,res) { if (Username !== "" && Username !== undefined) { if (req.body.message !== undefined && req.body.message !== '') { Messages.push({Username:Username,Texte:req.body.message}); } else { sendMessages(res); } } // SI on est pas connecté on envoi vers la page de connexion else { res.redirect('/'); } }); //appel pour l'affichage des messages app.post('/messages', function (req,res) { sendMessages(res); }); //---- // envoi des messages en réponse à un appel function sendMessages(res) { var val=""; for (var i=0 in Messages) { val += "<li>"+Messages[i].Username + ':' + Messages[i].Texte+"</li>"; } // On envoi les messages vers la page index res.send(val); }
TEST3
Le système semble parfaitement fonctionner. Il existe un bug qui fait que de temps à autre le dernier message envoyé, est à nouveau envoyé … Je n’ai pas recherché la cause de ce phénomène étrange.
Vous pouvez télécharger le code tout moisi ici (v3)
Conclusion
Nous avons un chat basique fonctionnel qui ne nous a couté quasi aucun effort (on aurait pu faire exactement la même chose tout aussi facilement en PHP). Il n’est absolument pas optimisé. Toutes les 3 secondes, un navigateur est susceptible d’appeler le serveur et chose encore plus drôle lorsque les sessions expirent les messages s’effacent (normal).
Autres soucis les messages sont stockés dans un tableau, si le serveur tombe, tous les messages sont perdus. De plus cela risque d’utiliser beaucoup de mémoire à la longue. On ne connait pas non plus la date et l’heure du post du message. SI on fait F5 on renvoie le dernier message. Bref ce n’est pas top, il s’agit d’un cas d’étude.
D’autre part le code pourrait connaitre de nombreuses optimisations. La mise en module par exemple pourrait en être une. L’optimisation de l’écriture du code lui-même avec l’utilisation objet des fonctions, etc…
L’avantage de l’avoir réalisé avec NodeJS est sa grande réactivité et vitesse.
Dans un prochain POST, on va ajouter une base de données pour ne plus perdre les messages. On va utiliser les sockets plutôt un petit Ajax, on va horodaté les messages.
Comments powered by CComment