Node.js, un nouvel écosystème basé sur JavaScript

C'est un serveur écrit en JavaScript, mais ce pourrait être beaucoup plus que cela.

Node.js peut fonctionner localement, sur Linux et Windows. Il interagit avec un navigateur et l'on peut donc créer des applications en JavaScript, fonctionnant localement ou à distance et qui utiliseront HTML 5 et Canvas comme interface. Nous allons développer cette possibilité et ses implications.

Node.js n'est pas vraiment un remplacement pour Apache mais plutôt un outil pour les webmasters qui veulent contrôler totalement ce qui se passe sur le serveur distant, ou disposer d'une sorte de serveur local pour des applications fonctionnant simultanément et partageant des données. MySpace est un exemple de site fonctionnant sous Node.js, avec le framework Express. Groupon à en 2013 migré son infrastructure de Rail à Node.js et devient un des plus grands sites fonctionnant avec ce système. Parmi les autres grands sites utilisant Node, citons Paypal, Yahoo.

Node.js est un serveur d'applications

C'est un serveur écrit en JavaScript, qui peut s'utiliser comme module d'un programme écrit dans tout autre langage.

Grâce au compilateur JIT V8, il peut interpréter des scripts en JavaScript. Il est lui-même interprété par V8. Techniquement, c'est une librairie ajoutée à V8 et encapsulée dans un programme de lancement.

Il réagit aux évènements, un thread est ouvert par chacun. Il fonctionne de façon asynchrone, chaque évènement déclenchant un processus exécuté indépendamment des autres. Il est aussi non-bloquant, ce qui veut dire que l'on n'a pas besoin de verrouiller quelque chose pour empêcher d'autres accès quand une opération est effectuée, comme c'est le cas en multi-threading.

On peut l'installer sur un serveur à la place d'Apache où on lui donnera les URL des pages à charger ou d'applications à exécuter. Celles-ci seront exécutées dans le navigateur sur le poste local.

On peut l'installer localement, plus facilement qu'Apache, c'est un fichier exécutable qu'il suffit de lancer en ligne de commande pour le rendre disponible au navigateur avec une IP locale et un numéro de port.

Il est moins complet qu'Apache, il faut quelquefois rajouter du code pour traiter des opérations qui sont effectuées d'emblées par Apache (pour la version 6.0 de Node.js), ou ajouter un framework.

Il est indépendant du protocole, peut utiliser HTTP pour fournir des pages HTML ou d'autres protocoles pour d'autres types d'applications.

Le fonctionnement est décrit dans le schéma ci-dessous. Un script JavaScript crée une instance de serveur et lui assigne un port, par lequel un navigateur ou autre agent utilisateur peut communiquer et interagir avec le script.

Diagramme de Node.js

On utilise node.js en lui donnant un programme JavaScript à interpréter

Supposons que l'on crée un script que l'on nommera monscript.js. On lance le serveur en ligne de commande ainsi:

node monscript.js

Le script doit contenir le code pour créer une instance de serveur, par exemple:

var http = require('http');
function f(request, response)
{
  response.writeHead(200, {'Content-Type': 'text/plain'});
  response.write(new Date() +'\nServeur en ligne...');
  response.end();
}
var server = http.createServer(f);
server.listen(1000);

On crée un serveur de cette façon:

  1. Charger le module http pour un serveur suivant ce protocole, et l'assigner à une variable.
  2. Créer un serveur http en appelant la méthode createServer du module http, par la commande: server.createServer().
    Cette méthode à pour paramètre une fonction qui est appelée par l'objet server avec en paramètre deux objets (auxquels sont assignés les noms request et response).
  3. La méthode writeHead de l'objet response crée une en-tête avec le code d'état HTTP 200 qui signifie OK.
  4. La méthode write affiche un message.
  5. La méthode end marque la fin de l'envoi de données par le serveur (pas de la communication). Elle peut aussi afficher un message comme write.
  6. L'objet request n'est pas utilisé ici, mais il est donne accès à des fonctions utiles. Voir le prochain exemple.
  7. On assigne un port avec la méthode listen du serveur créé: server.listen(1000).
    Le numéro 1000 est un exemple, d'autres valeurs comprises entre 0 et 65535 sont possibles, pouvu que le numéro ne soit pas déjà utilisé par un autre service.

Le paramètre de createServer est une fonction qui envoie un message à l'utilisateur. On peut le déclarer comme fonction anonyme, elle est utilisée comme paramètre par une fonction interne à l'objet server et qui contient les objets request et response qui restent assignés après le retour de la fonction f.
Le code tire profit des closures inhérentes à JavaScript. La closure consiste à donner une portée globale aux variables déclarées dans une fonction, mais les rendant accessibles seulement à cette fonction. Si on appelle plusieurs fois la fonction, les variables conservent leur valeur d'un appel à l'autre. Ainsi un processus peut s'exécuter en sandbox, indépendamment des autres.

Pour accéder à l'application, taper dans la barre d'URL d'un navigateur:

127.0.0.1:1000

Ce qui correspond à l'IP locale suivie du numéro de port choisi. Vous verrez affiché la date et l'heure, suivis du message "Serveur en ligne...". Ou encore:

localhost:1000

Cette URL restera disponible tant que la commande node monscript.js n'est pas annulée ou la fenêtre de ligne de commande fermée. Si l'on relance un autre script, avec par exemple node script2.js, en rechargeant la page on obtient alors l'accès à ce nouveau script.

Démonstration: Obtenir la persistance des données

Un script pour montrer comment les données peuvent persister d'une connexion à l'autre.

Pour commencer, on va compléter l'en-tête du script précédent afin de supporter les accents et autres codes étrangers pour pouvoir intégrer du texte à notre interface simplifiée:

  response.writeHead(200, {'Content-Type': 'text/plain;charset=utf-8'});

Le charset UTF-8 permet de supporter la plupart des caractères.

Nous allons ajouter un compteur de connexions et afficher le compteur, ainsi on peut vérifier que les données créées lors d'une connexion sont conservées pour la suivante, ce qui est indispensable avant de pouvoir partager des données entre applications.

Pour tester l'exemple, recharger plusieurs fois la page dans le navigateur avec l'URL donnée précédemment.

var http = require('http');
var counter = 0;
function f(req, response)
{
  if(request.url == '/favicon.ico') return;
  response.writeHead(200, {'Content-Type': 'text/plain;charset=utf-8'});
  if(counter == 0)
    response.write(new Date() +'\nServeur en ligne...\nPremière connexion.');
  else
    response.write((counter + 1) + " ème connexion.");
  counter++;
  response.end();
}
var server = http.createServer(f);
server.listen(1000);

Counter est une variable globale. Lors de la première connexion, le message d'introduction d'affiche, lors des suivantes, seul le numéro de connexion est affiché.

La première ligne...

  if(request.url == '/favicon.ico') return;	

...sert à supprimer un effet indésirable: le fait que le navigateur, quand on charge une page, fait deux requêtes successives, l'une pour la page, l'autre pour la favicon, ce qui incrémente le compteur deux fois!

On peut accéder à l'URL à partir de plusieurs navigateurs tout en conservant la persistance des données.

On peut aussi accéder au serveur sans navigateur. On peut par exemple, localement, avec un script en PHP, utiliser curl pour interagir avec le serveur, en même temps qu'avec un navigateur. Cela sera l'objet d'un autre article.

Tant que le serveur reste actif (lorsqu'il est en ligne il est sensé le rester en permanence), on peut communiquer avec différents navigateurs ou d'autres sortes d'agents utilisateurs.

Prochaine étape: Comment réaliser un serveur de pages ou d'applications avec Node.js.

Obtenir le code source

Modules utiles

Grâce à npm qui est inclut dans l'archive, on peut ajouter automatiquement des modules pour compléter le serveur.

Ressources et informations