Server Side JavaScript
Partie 2: le module Express
Michel Buffa
Avant tout: objets prédéfinis dans NodeJS
Souvent utilisés avec Express:
__dirname : répertoire courant
Exemple: res.sendfile(__dirname + '/index.html');�
__filename : nom du fichier qui exécute le code serveur
Express: HTTP, routage, Web Services, templates
Le module Express est un des plus populaires
Installer avec :
$ npm install -save express
Permet de définir facilement des “routes”, de servir des fichiers statiques, de faire des Web Services renvoyant/acceptant du JSON…
Premier exemple:
var express = require('express');�var app = express();��app.get('/', (req, res) => {� res.send('Hello World');�})��var server = app.listen(8085, function () {� var host = server.address().address� var port = server.address().port� console.log("Serveur écoute sur http://%s:%s", host, port)�})
app.get, app.post, app.put, app.delete...
// This responds to a GET request with "Hello World" on the homepage�app.get('/', (req, res) => {� console.log("Got a GET request for the homepage");� res.send('Hello GET');�})��// This responds to a POST request for the homepage�app.post('/', (req, res) => {� console.log("Got a POST request for the homepage");� res.send('Hello POST');�})�
Autres exemples: support d’expressions régulières
// This responds a GET request for the /list_user page.�app.get('/list_user', (req, res) => {� console.log("Got a GET request for /list_user");� res.send('Page Listing');�})��// This responds a GET request for abcd, abxcd, ab123cd, and so on�app.get('/ab*cd', (req, res) => { � console.log("Got a GET request for /ab*cd");� res.send('Page Pattern Match');�})
Avec la dernière route..
On peut aussi faire cela...
// routing�app.get(/\/track\/(\w+)\/(?:sound|visualisation)\/((\w|.)+)/, � (req, res) => {� res.sendfile(__dirname + '/' + TRACKS_PATH + req.params[0] � + '/' + req.params[1]);�});
Matche:
Récupérer des bouts de chemin dans l’URL
Avec http://localhost:8085/track/HighwayToHell
app.get('/track/:id', (req, res) => {� var id = req.params.id; // vaut HighwayToHell�� // Faire quelque chose avec id, aller chercher l'objet dans une BD� // etc...�});
Récupérer des paramètres HTTP
Avec http://localhost:8085/track/HighwayToHell?format=mp3�
app.get('/track/:id', (req, res) => {� var id = req.params.id; // params pour chemin dans URL� var format = req.query.format; // query pour params HTTP
� // Faire quelque chose avec id et la valeur du format,
// aller chercher l'objet dans une BD� // etc...�});
Envoi d’un fichier statique par HTTP sans Express
http.createServer( (request, response) => { � // Parse the request containing file name� var pathname = url.parse(request.url).pathname;� � // Print the name of the file for which request is made.� console.log("Request for " + pathname + " received.");� � // Read the requested file content from file system� fs.readFile(pathname.substr(1), (err, data) => {� if (err) {� console.log(err);� // HTTP Status: 404 : NOT FOUND� // Content Type: text/plain� response.writeHead(404, {'Content-Type': 'text/html'});� }else{ � //Page found � // HTTP Status: 200 : OK� // Content Type: text/plain� response.writeHead(200, {'Content-Type': 'text/html'}); � � // Write the content of the file to response body� response.write(data.toString()); � }� // Send the response body � response.end();� }); �}).listen(8081);
Fichiers statiques avec Express
var express = require('express');�var app = express();�// avec cette ligne, index.html est par defaut la page d’accueil
app.use(express.static('public')); // ICI IMPORTANT !�
// Avec la règle ci-dessous on peut redéfinir la page d’accueil�app.get('/', (req, res) => { // Page d’accueil� res.sendFile(__dirname + "/public/maPage.html");�});�var server = app.listen(8081, function () {})�
Avec l’exemple précédent
Si on a la hiérarchie suivante :�
node_modules�server.js�public/
public/index.html�public/images�public/images/logo.png�
Le serveur répondra à :
http://localhost:8081/images/logo.png
http://localhost:8081 renverra public/index.html
Formulaires classiques avec POST
<form action="process_post" method="POST">�First Name: <input type="text" name="first_name"> <br>�Last Name: <input type="text" name="last_name">�<input type="submit" value="Submit">�</form>
Utilisation du module body-parser
var bodyParser = require('body-parser');
�// Create application/x-www-form-urlencoded parser�var urlencodedParser = bodyParser.urlencoded({ extended: false })
�app.post('/process_post', urlencodedParser, (req, res) => {� // Prepare output in JSON format� response = {� first_name:req.body.first_name,� last_name:req.body.last_name� };� console.log(JSON.stringify(response));� res.end(JSON.stringify(response)); // plus tard, ça ira dans MongoDB par exemple...�})
Exemple de route POST pour formulaire multipart
<form action="/api/restaurants" method="post"
enctype="multipart/form-data">
Nom: <input type="text" name="nom"><br>
Cuisine: <input type="text" name="cuisine"><br>
<input type="submit" value="Submit">
</form>
Exemple de route POST pour formulaire multipart
// pour les formulaires multiparts
var multer = require('multer');
var multerData = multer();
…
app.post('/api/restaurants', multerData.fields([]), (req, res) => {
let nom = req.body.nom;
let cuisine = req.body.cuisine;
let reponse = {
msg: "J'insère un restaurant nom = " + nom + " cuisine = " + cuisine,
data: "id du restaurant inséré " + Math.random(),
err: ""
}
res.send(JSON.stringify(reponse));
}
Ex envoi de fichier multipart...
<input id="file" type="file" multiple/>
<script>
var fileInput = document.querySelector('#file');
fileInput.onchange = function() {
// requête Ajax vers serveur pour envoyer les fichiers sélectionnés
// …
}
</script>
Upload de fichiers, formulaires multiparts
Le module MULTER est celui que je vous recommande !
var multer = require("multer");�// multer configuration: destination, filename customization, etc.�var storage = multer.diskStorage({� destination: "./public/uploads",� filename: function (req, file, cb) {� cb(null, file.originalname + '-' + Date.now());� }�});�// instaciation of a multer processor�var upload = multer({ storage: storage });�
Exemple pour de l’envoi de fichiers multiples
app.post('/api/file', upload.array('file'), (req, res) => {� console.log("received " + req.files.length + " files");// form files� for(var i=0; i < req.files.length; i++) {� console.log("### " + req.files[i].path);� }� console.log("The URL for the file is:" +
"localhost:3000\\"+req.file.path);� res.status(204).end(); �});
Extrait du code JavaScript du client
fileInput.onchange = function() {� var data = new FormData();� for(var i=0; i < fileInput.files.length; i++)� data.append('file', fileInput.files[i]); // tous le même nom !�� fetch(url, {
method: 'post',
body: data
});� };
L’exemple précédent marche aussi en Ajax / Xhr2
Dans le TP vous ferez tourner cet exemple complet, avec un client Ajax / Xhr2
Sessions HTTP et express
var express = require('express');�var app = express();��app.use(express.cookieParser());�app.use(express.session({secret: '1234567890QWERTY'}));��app.get('/awesome', (req, res) => {� if(req.session.lastPage) {� res.write('Last page was: ' + req.session.lastPage + '. ');� }� req.session.lastPage = '/awesome';� res.send('Your Awesome.');�});
Sessions HTTP et express, sessions persistantes
On peut stocker la session dans un “store” externe comme Redis
On peut aussi la stocker dans MongoDB
Express et templates
Le plus souvent: NodeJS sert à des applications fullJS / Ajax et on fait des templates côté client, le serveur ne renvoyant que du JSON à part pour quelques pages HTML statiques (page d’accueil par exemple).
Il existe néanmoins des langages de templates: JADE, EJS, c’est pas compliqué, c’est comme les pages JSPs à peu de choses près !
Je n’aime pas trop cela… on se croirait revenu aux années 1997 ou aux débuts de PHP.
Exemple avec JADE
Exemple avec JADE, suite...
Fichier views/index.jade :
html� head� title!= title� body� h1!= message�
app.get('/', (req, res) => {� res.render('index',
{
title: 'Hey',
message: 'Hello there!'
}
);�});
Exemple avec EJS
Exemple avec JADE, suite...
Fichier views/index.ejs :
<h1>Je vais compter jusqu'à <%= compteur %></h1>�<p><%� for(var i = 1 ; i <= compteur ; i++) {� %>� <%= i %>... �<% } %></p>�<p>Tant que j'y suis, je prends un nom au hasard qu'on m'a envoyé :�<%= noms[Math.round(Math.random() * (noms.length - 1))] %>�</p>
app.get('/compter/:nombre',(req, res) => {� var lesNoms = ['Robert',
'Jacques', 'David'];� res.render(index.ejs',
{
compteur: req.params.nombre,
noms: lesNoms
});�});
Vous en pensez quoi ?
Sérieusement….
Qui peut encore écrire du code comme ça ??????
En 1999 SUN Microsystem avait déjà changé la syntaxe des JSPs version 1, PHP avait déjà recommandé de ne plus faire de code spaghetti en mélangeant HTML et PHP…
Et je vois çà en 2021 ???
Bonne solution : vues côté client à 100% !
Utiliser le DOM “standard”
Ou via jQuery
Ou via une framework MVC moderne (backbone, angularJS, etc.) qui va faire du binding entre: web services, données JavaScript et vues