Node.js
Applications Web avec Express
Recherche…
Introduction
Express est une infrastructure d'application Web Node.js minimale et flexible, fournissant un ensemble robuste de fonctionnalités pour la création d'applications Web.
Le site officiel d'Express est expressjs.com . La source peut être trouvée sur GitHub .
Syntaxe
- app.get (chemin [, middleware], callback [, callback ...])
- app.put (chemin [, middleware], callback [, callback ...])
- app.post (chemin [, middleware], callback [, callback ...])
- app ['delete'] (chemin [, middleware], callback [, callback ...])
- app.use (chemin [, middleware], callback [, callback ...])
- app.use (rappel)
Paramètres
Paramètre | Détails |
---|---|
path | Spécifie la portion de chemin ou l'URL que le rappel donné va gérer. |
middleware | Une ou plusieurs fonctions qui seront appelées avant le rappel. Essentiellement un chaînage de plusieurs fonctions de callback . Utile pour une manipulation plus spécifique, par exemple une autorisation ou un traitement des erreurs. |
callback | Une fonction qui sera utilisée pour gérer les demandes sur le path spécifié. Il sera appelé comme callback(request, response, next) , où request , response et next sont décrits ci-dessous. |
request rappel | Un objet encapsulant des détails sur la requête HTTP que le rappel est appelé à gérer. |
response | Un objet utilisé pour spécifier comment le serveur doit répondre à la demande. |
next | Un rappel qui passe le contrôle au prochain itinéraire correspondant. Il accepte un objet d'erreur facultatif. |
Commencer
Vous devez d'abord créer un répertoire, y accéder dans votre shell et installer Express en utilisant npm en exécutant npm install express --save
Créez un fichier et nommez-le app.js
et ajoutez le code suivant qui crée un nouveau serveur Express et lui ajoute un point de terminaison ( /ping
) avec la méthode app.get
:
const express = require('express');
const app = express();
app.get('/ping', (request, response) => {
response.send('pong');
});
app.listen(8080, 'localhost');
Pour exécuter votre script, utilisez la commande suivante dans votre shell:
> node app.js
Votre application acceptera les connexions sur le port localhost 8080. Si l'argument hostname de app.listen
est omis, le serveur acceptera les connexions sur l'adresse IP de la machine et sur localhost. Si la valeur du port est 0, le système d'exploitation attribuera un port disponible.
Une fois que votre script est en cours d'exécution, vous pouvez le tester dans un shell pour confirmer que vous obtenez la réponse attendue, "pong", du serveur:
> curl http://localhost:8080/ping
pong
Vous pouvez également ouvrir un navigateur Web, accédez à l'URL http: // localhost: 8080 / ping pour afficher la sortie
Routage de base
Commencez par créer une application express:
const express = require('express');
const app = express();
Ensuite, vous pouvez définir des itinéraires comme celui-ci:
app.get('/someUri', function (req, res, next) {})
Cette structure fonctionne pour toutes les méthodes HTTP et attend un chemin comme premier argument et un gestionnaire pour ce chemin qui reçoit les objets de requête et de réponse. Donc, pour les méthodes HTTP de base, ce sont les routes
// GET www.domain.com/myPath
app.get('/myPath', function (req, res, next) {})
// POST www.domain.com/myPath
app.post('/myPath', function (req, res, next) {})
// PUT www.domain.com/myPath
app.put('/myPath', function (req, res, next) {})
// DELETE www.domain.com/myPath
app.delete('/myPath', function (req, res, next) {})
Vous pouvez vérifier la liste complète des verbes pris en charge ici . Si vous souhaitez définir le même comportement pour une route et toutes les méthodes HTTP, vous pouvez utiliser:
app.all('/myPath', function (req, res, next) {})
ou
app.use('/myPath', function (req, res, next) {})
ou
app.use('*', function (req, res, next) {})
// * wildcard will route for all paths
Vous pouvez enchaîner vos définitions de route pour un chemin unique
app.route('/myPath')
.get(function (req, res, next) {})
.post(function (req, res, next) {})
.put(function (req, res, next) {})
Vous pouvez également ajouter des fonctions à toute méthode HTTP. Ils s'exécuteront avant le rappel final et prendront les paramètres (req, res, next) comme arguments.
// GET www.domain.com/myPath
app.get('/myPath', myFunction, function (req, res, next) {})
Vos derniers rappels peuvent être stockés dans un fichier externe pour éviter de mettre trop de code dans un fichier:
// other.js
exports.doSomething = function(req, res, next) {/* do some stuff */};
Et puis dans le fichier contenant vos itinéraires:
const other = require('./other.js');
app.get('/someUri', myFunction, other.doSomething);
Cela rendra votre code beaucoup plus propre.
Obtenir des informations à partir de la demande
Pour obtenir des informations de la part de l'url requérante (notez que req
est l'objet de requête dans la fonction de gestionnaire des itinéraires). Considérez cette définition /settings/:user_id
et cet exemple particulier /settings/32135?field=name
// get the full path
req.originalUrl // => /settings/32135?field=name
// get the user_id param
req.params.user_id // => 32135
// get the query value of the field
req.query.field // => 'name'
Vous pouvez également obtenir les en-têtes de la requête, comme ceci
req.get('Content-Type')
// "text/plain"
Pour simplifier l'obtention d'autres informations, vous pouvez utiliser des middlewares. Par exemple, pour obtenir les informations sur le corps de la requête, vous pouvez utiliser le middleware analyseur de corps , qui transformera le corps de la requête brute en un format utilisable.
var app = require('express')();
var bodyParser = require('body-parser');
app.use(bodyParser.json()); // for parsing application/json
app.use(bodyParser.urlencoded({ extended: true })); // for parsing application/x-www-form-urlencoded
Maintenant, supposons une requête comme celle-ci
PUT /settings/32135
{
"name": "Peter"
}
Vous pouvez accéder au nom affiché comme ceci
req.body.name
// "Peter"
De la même manière, vous pouvez accéder aux cookies de la requête, vous avez également besoin d'un middleware comme cookie-parser
req.cookies.name
Application express modulaire
Pour rendre les applications de modulaires d’application web express modulaires:
Module:
// greet.js
const express = require('express');
module.exports = function(options = {}) { // Router factory
const router = express.Router();
router.get('/greet', (req, res, next) => {
res.end(options.greeting);
});
return router;
};
Application:
// app.js
const express = require('express');
const greetMiddleware = require('./greet.js');
express()
.use('/api/v1/', greetMiddleware({ greeting:'Hello world' }))
.listen(8080);
Cela rendra votre application modulable, personnalisable et votre code réutilisable.
Lorsque vous accédez à http://<hostname>:8080/api/v1/greet
le résultat sera Hello world
Exemple plus compliqué
Exemple avec des services qui montrent les avantages d'une usine middleware.
Module:
// greet.js
const express = require('express');
module.exports = function(options = {}) { // Router factory
const router = express.Router();
// Get controller
const {service} = options;
router.get('/greet', (req, res, next) => {
res.end(
service.createGreeting(req.query.name || 'Stranger')
);
});
return router;
};
Application:
// app.js
const express = require('express');
const greetMiddleware = require('./greet.js');
class GreetingService {
constructor(greeting = 'Hello') {
this.greeting = greeting;
}
createGreeting(name) {
return `${this.greeting}, ${name}!`;
}
}
express()
.use('/api/v1/service1', greetMiddleware({
service: new GreetingService('Hello'),
}))
.use('/api/v1/service2', greetMiddleware({
service: new GreetingService('Hi'),
}))
.listen(8080);
Lorsque vous accédez à http://<hostname>:8080/api/v1/service1/greet?name=World
le résultat sera Hello, World
et vous accéderez à http://<hostname>:8080/api/v1/service2/greet?name=World
La sortie sera Hi, World
.
Utiliser un moteur de template
Utiliser un moteur de template
Le code suivant va configurer Jade comme moteur de template. (Remarque: Jade a été renommé pug
en décembre 2015.)
const express = require('express'); //Imports the express module
const app = express(); //Creates an instance of the express module
const PORT = 3000; //Randomly chosen port
app.set('view engine','jade'); //Sets jade as the View Engine / Template Engine
app.set('views','src/views'); //Sets the directory where all the views (.jade files) are stored.
//Creates a Root Route
app.get('/',function(req, res){
res.render('index'); //renders the index.jade file into html and returns as a response. The render function optionally takes the data to pass to the view.
});
//Starts the Express server with a callback
app.listen(PORT, function(err) {
if (!err) {
console.log('Server is running at port', PORT);
} else {
console.log(JSON.stringify(err));
}
});
De même, d'autres moteurs de gabarit pourraient être utilisés, tels que des Handlebars
( hbs
) ou des ejs
. N'oubliez pas de npm install
le moteur de template aussi. Pour les guidons, nous utilisons un paquetage hbs
, pour Jade, nous avons un paquet jade
et pour EJS, nous avons un paquet ejs
.
Exemple de modèle EJS
Avec EJS (comme les autres modèles express), vous pouvez exécuter du code serveur et accéder à vos variables serveur à partir de votre code HTML.
Dans EJS, on utilise " <%
" comme balise de début et " %>
" comme balise de fin, les variables transmises comme les paramètres de rendu sont accessibles avec <%=var_name%>
Par exemple, si vous avez une baie de consommables dans votre code serveur
vous pouvez le parcourir en utilisant
<h1><%= title %></h1>
<ul>
<% for(var i=0; i<supplies.length; i++) { %>
<li>
<a href='supplies/<%= supplies[i] %>'>
<%= supplies[i] %>
</a>
</li>
<% } %>
Comme vous pouvez le voir dans l'exemple chaque fois que vous passez le code côté serveur et HTML que vous devez fermer la balise EJS actuelle et ouvrir un nouveau plus tard, nous voulions créer li
l' intérieur de la for
commande si nous devions fermer notre étiquette EJS à la fin du for
et créer une nouvelle balise juste pour les accolades
un autre exemple
si nous voulons mettre en entrée la version par défaut pour être une variable du côté serveur, nous utilisons <%=
par exemple:
Message:<br>
<input type="text" value="<%= message %>" name="message" required>
Ici, la variable de message transmise de votre côté serveur sera la valeur par défaut de votre saisie. Notez que si vous ne transmettez pas la variable de message depuis votre serveur, EJS lancera une exception. Vous pouvez passer des paramètres à l'aide de res.render('index', {message: message});
(pour le fichier ejs appelé index.ejs).
Dans les balises EJS, vous pouvez également utiliser if
, while
ou toute autre commande javascript souhaitée.
API JSON avec ExpressJS
var express = require('express');
var cors = require('cors'); // Use cors module for enable Cross-origin resource sharing
var app = express();
app.use(cors()); // for all routes
var port = process.env.PORT || 8080;
app.get('/', function(req, res) {
var info = {
'string_value': 'StackOverflow',
'number_value': 8476
}
res.json(info);
// or
/* res.send(JSON.stringify({
string_value: 'StackOverflow',
number_value: 8476
})) */
//you can add a status code to the json response
/* res.status(200).json(info) */
})
app.listen(port, function() {
console.log('Node.js listening on port ' + port)
})
Sur http://localhost:8080/
output object
{
string_value: "StackOverflow",
number_value: 8476
}
Servant des fichiers statiques
Lors de la création d'un serveur Web avec Express, il est souvent nécessaire de fournir une combinaison de contenu dynamique et de fichiers statiques.
Par exemple, vous pouvez avoir index.html et script.js qui sont des fichiers statiques conservés dans le système de fichiers.
Il est courant d'utiliser le dossier nommé 'public' pour avoir des fichiers statiques. Dans ce cas, la structure des dossiers peut ressembler à ceci:
project root
├── server.js
├── package.json
└── public
├── index.html
└── script.js
Voici comment configurer Express pour servir des fichiers statiques:
const express = require('express');
const app = express();
app.use(express.static('public'));
Remarque: une fois le dossier configuré, index.html, script.js et tous les fichiers du dossier "public" seront disponibles dans le chemin racine (vous ne devez pas spécifier /public/
dans l'URL). En effet, express recherche les fichiers relatifs au dossier statique configuré. Vous pouvez spécifier le préfixe de chemin virtuel comme indiqué ci-dessous:
app.use('/static', express.static('public'));
rendra les ressources disponibles sous le préfixe /static/
.
Plusieurs dossiers
Il est possible de définir plusieurs dossiers en même temps:
app.use(express.static('public'));
app.use(express.static('images'));
app.use(express.static('files'));
Lors de la diffusion des ressources, Express examinera le dossier dans l'ordre de définition. Dans le cas de fichiers portant le même nom, celui du premier dossier correspondant sera servi.
Routes nommées dans le style Django
Un gros problème est que les itinéraires nommés de valeur ne sont pas pris en charge par Express. La solution consiste à installer un package tiers pris en charge, par exemple express-reverse :
npm install express-reverse
Branchez-le dans votre projet:
var app = require('express')();
require('express-reverse')(app);
Ensuite, utilisez-le comme:
app.get('test', '/hello', function(req, res) {
res.end('hello');
});
L'inconvénient de cette approche est que vous ne pouvez pas utiliser le module route
Express comme indiqué dans Utilisation avancée du routeur . La solution consiste à transmettre votre app
tant que paramètre à votre fabrique de routeurs:
require('./middlewares/routing')(app);
Et l'utiliser comme:
module.exports = (app) => {
app.get('test', '/hello', function(req, res) {
res.end('hello');
});
};
Vous pouvez désormais comprendre comment définir des fonctions pour le fusionner avec les espaces de noms personnalisés spécifiés et pointer vers les contrôleurs appropriés.
La gestion des erreurs
Gestion des erreurs de base
Par défaut, Express recherchera une vue "erreur" dans le répertoire /views
pour effectuer le rendu. Créez simplement la vue 'error' et placez-la dans le répertoire views pour gérer les erreurs. Les erreurs sont écrites avec le message d'erreur, l'état et la trace de la pile, par exemple:
views / error.pug
html
body
h1= message
h2= error.status
p= error.stack
Gestion avancée des erreurs
Définissez les fonctions de gestion des erreurs à la toute fin de la pile de fonctions du middleware. Celles-ci ont quatre arguments au lieu de trois (err, req, res, next)
par exemple:
app.js
// catch 404 and forward to error handler
app.use(function(req, res, next) {
var err = new Error('Not Found');
err.status = 404;
//pass error to the next matching route.
next(err);
});
// handle error, print stacktrace
app.use(function(err, req, res, next) {
res.status(err.status || 500);
res.render('error', {
message: err.message,
error: err
});
});
Vous pouvez définir plusieurs fonctions de middleware de gestion des erreurs, comme vous le feriez avec des fonctions de middleware standard.
Utiliser le middleware et le prochain rappel
Express transmet un rappel next
à chaque fonction de gestionnaire de routage et de middleware qui peut être utilisée pour rompre la logique des itinéraires uniques entre plusieurs gestionnaires. L'appel de next()
sans arguments indique à express de continuer vers le middleware ou le gestionnaire de route suivant. L'appel à next(err)
avec une erreur déclenchera tout middleware de gestionnaire d'erreurs. L'appel next('route')
contournera tout middleware suivant sur l'itinéraire actuel et passera à l'itinéraire suivant. Cela permet de découpler la logique de domaine en composants réutilisables, autonomes, plus simples à tester et plus faciles à gérer et à modifier.
Plusieurs itinéraires correspondants
Les demandes à /api/foo
ou à /api/bar
exécuteront le gestionnaire initial pour rechercher le membre, puis passer le contrôle au gestionnaire réel pour chaque route.
app.get('/api', function(req, res, next) {
// Both /api/foo and /api/bar will run this
lookupMember(function(err, member) {
if (err) return next(err);
req.member = member;
next();
});
});
app.get('/api/foo', function(req, res, next) {
// Only /api/foo will run this
doSomethingWithMember(req.member);
});
app.get('/api/bar', function(req, res, next) {
// Only /api/bar will run this
doSomethingDifferentWithMember(req.member);
});
Gestionnaire d'erreur
Les gestionnaires d'erreurs sont des middlewares avec la function(err, req, res, next)
signature function(err, req, res, next)
. Ils peuvent être configurés par route (par exemple, app.get('/foo', function(err, req, res, next)
) mais généralement, un seul gestionnaire d’erreur qui affiche une page d’erreur suffit.
app.get('/foo', function(req, res, next) {
doSomethingAsync(function(err, data) {
if (err) return next(err);
renderPage(data);
});
});
// In the case that doSomethingAsync return an error, this special
// error handler middleware will be called with the error as the
// first parameter.
app.use(function(err, req, res, next) {
renderErrorPage(err);
});
Middleware
Chacune des fonctions ci-dessus est en fait une fonction de middleware exécutée à chaque fois qu'une requête correspond à la route définie, mais un nombre quelconque de fonctions de middleware peut être défini sur une seule route. Cela permet de définir le middleware dans des fichiers séparés et de réutiliser la logique commune sur plusieurs routes.
app.get('/bananas', function(req, res, next) {
getMember(function(err, member) {
if (err) return next(err);
// If there's no member, don't try to look
// up data. Just go render the page now.
if (!member) return next('route');
// Otherwise, call the next middleware and fetch
// the member's data.
req.member = member;
next();
});
}, function(req, res, next) {
getMemberData(req.member, function(err, data) {
if (err) return next(err);
// If this member has no data, don't bother
// parsing it. Just go render the page now.
if (!data) return next('route');
// Otherwise, call the next middleware and parse
// the member's data. THEN render the page.
req.member.data = data;
next();
});
}, function(req, res, next) {
req.member.parsedData = parseMemberData(req.member.data);
next();
});
app.get('/bananas', function(req, res, next) {
renderBananas(req.member);
});
Dans cet exemple, chaque fonction de middleware serait soit dans son propre fichier, soit dans une variable ailleurs dans le fichier, de manière à pouvoir être réutilisée dans d'autres itinéraires.
La gestion des erreurs
Les documents de base peuvent être trouvés ici
app.get('/path/:id(\\d+)', function (req, res, next) { // please note: "next" is passed
if (req.params.id == 0) // validate param
return next(new Error('Id is 0')); // go to first Error handler, see below
// Catch error on sync operation
var data;
try {
data = JSON.parse('/file.json');
} catch (err) {
return next(err);
}
// If some critical error then stop application
if (!data)
throw new Error('Smth wrong');
// If you need send extra info to Error handler
// then send custom error (see Appendix B)
if (smth)
next(new MyError('smth wrong', arg1, arg2))
// Finish request by res.render or res.end
res.status(200).end('OK');
});
// Be sure: order of app.use have matter
// Error handler
app.use(function(err, req, res, next)) {
if (smth-check, e.g. req.url != 'POST')
return next(err); // go-to Error handler 2.
console.log(req.url, err.message);
if (req.xhr) // if req via ajax then send json else render error-page
res.json(err);
else
res.render('error.html', {error: err.message});
});
// Error handler 2
app.use(function(err, req, res, next)) {
// do smth here e.g. check that error is MyError
if (err instanceof MyError) {
console.log(err.message, err.arg1, err.arg2);
}
...
res.end();
});
Annexe A
// "In Express, 404 responses are not the result of an error,
// so the error-handler middleware will not capture them."
// You can change it.
app.use(function(req, res, next) {
next(new Error(404));
});
Appendice B
// How to define custom error
var util = require('util');
...
function MyError(message, arg1, arg2) {
this.message = message;
this.arg1 = arg1;
this.arg2 = arg2;
Error.captureStackTrace(this, MyError);
}
util.inherits(MyError, Error);
MyError.prototype.name = 'MyError';
Hook: Comment exécuter du code avant toute demande et après toute res
app.use()
et le middleware peuvent être utilisés pour "before" et une combinaison des événements close et finish peut être utilisée pour "after".
app.use(function (req, res, next) {
function afterResponse() {
res.removeListener('finish', afterResponse);
res.removeListener('close', afterResponse);
// actions after response
}
res.on('finish', afterResponse);
res.on('close', afterResponse);
// action before request
// eventually calling `next()`
next();
});
...
app.use(app.router);
Un exemple de ceci est le middleware de l' enregistreur , qui sera ajouté au journal après la réponse par défaut.
Assurez-vous simplement que ce "middleware" est utilisé avant app.router
car l'ordre compte.
Le message original est ici
Gestion des requêtes POST
Tout comme vous gérez les demandes d'obtention dans Express avec la méthode app.get, vous pouvez utiliser la méthode app.post pour gérer les demandes de publication.
Mais avant de pouvoir traiter les requêtes POST, vous devrez utiliser le middleware body-parser
. Il analyse simplement le corps des requêtes POST
, PUT
, DELETE
et autres.
Body-Parser
middleware Body-Parser
analyse le corps de la requête et le transforme en objet disponible dans req.body
var bodyParser = require('body-parser');
const express = require('express');
const app = express();
// Parses the body for POST, PUT, DELETE, etc.
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.post('/post-data-here', function(req, res, next){
console.log(req.body); // req.body contains the parsed body of the request.
});
app.listen(8080, 'localhost');
Définition de cookies avec un cookie-parser
Voici un exemple de configuration et de lecture de cookies à l'aide du module cookie-parser :
var express = require('express');
var cookieParser = require('cookie-parser'); // module for parsing cookies
var app = express();
app.use(cookieParser());
app.get('/setcookie', function(req, res){
// setting cookies
res.cookie('username', 'john doe', { maxAge: 900000, httpOnly: true });
return res.send('Cookie has been set');
});
app.get('/getcookie', function(req, res) {
var username = req.cookies['username'];
if (username) {
return res.send(username);
}
return res.send('No cookie found');
});
app.listen(3000);
Middleware personnalisé dans Express
Dans Express, vous pouvez définir des middlewares pouvant être utilisés pour vérifier les requêtes ou définir des en-têtes en réponse.
app.use(function(req, res, next){ }); // signature
Exemple
Le code suivant ajoute l' user
à l'objet de requête et le transmet au prochain itinéraire correspondant.
var express = require('express');
var app = express();
//each request will pass through it
app.use(function(req, res, next){
req.user = 'testuser';
next(); // it will pass the control to next matching route
});
app.get('/', function(req, res){
var user = req.user;
console.log(user); // testuser
return res.send(user);
});
app.listen(3000);
Gestion des erreurs dans Express
Dans Express, vous pouvez définir un gestionnaire d'erreurs unifié pour la gestion des erreurs survenues dans l'application. Définissez ensuite le gestionnaire à la fin de toutes les routes et du code logique.
Exemple
var express = require('express');
var app = express();
//GET /names/john
app.get('/names/:name', function(req, res, next){
if (req.params.name == 'john'){
return res.send('Valid Name');
} else{
next(new Error('Not valid name')); //pass to error handler
}
});
//error handler
app.use(function(err, req, res, next){
console.log(err.stack); // e.g., Not valid name
return res.status(500).send('Internal Server Occured');
});
app.listen(3000);
Ajout de middleware
Les fonctions de middleware sont des fonctions qui ont accès à l'objet de requête (req), à l'objet de réponse (res) et à la fonction de middleware suivante dans le cycle demande-réponse de l'application.
Les fonctions middleware peuvent exécuter n'importe quel code, apporter des modifications aux objets res
et req
, mettre fin au cycle de réponse et appeler le prochain middleware.
Un exemple très courant de middleware est le module cors
. Pour ajouter le support CORS, installez-le simplement, exigez-le et mettez cette ligne:
app.use(cors());
avant tout routeurs ou fonctions de routage.
Bonjour le monde
Ici, nous créons un serveur de base hello world en utilisant Express. Itinéraires:
- '/'
- '/ wiki'
Et pour le reste donnera "404", c'est-à-dire la page introuvable.
'use strict';
const port = process.env.PORT || 3000;
var app = require('express')();
app.listen(port);
app.get('/',(req,res)=>res.send('HelloWorld!'));
app.get('/wiki',(req,res)=>res.send('This is wiki page.'));
app.use((req,res)=>res.send('404-PageNotFound'));
Remarque: Nous avons placé 404 route comme dernier itinéraire car Express stocke les itinéraires dans l’ordre et les traite pour chaque requête de manière séquentielle.