Express : middlewares
Un middleware est une fonction (req, res, next) qui s’exécute entre la réception de la requête et la réponse. Les middlewares forment une chaîne ; chacun appelle next() pour passer au suivant, ou répond lui-même.
Écrire un middleware
Section intitulée « Écrire un middleware »function journal(req, res, next) { const debut = Date.now(); res.on('finish', () => { console.log( `${req.method} ${req.originalUrl} ${res.statusCode} ${Date.now() - debut} ms`, ); }); next();}
app.use(journal);Un middleware doit soit appeler next(), soit envoyer une réponse : sinon la requête reste en attente.
app.use(journal); // toutes les routesapp.use('/api', verifierJeton); // routes sous /apiapp.get('/admin', verifierJeton, (req, res) => res.send('admin')); // une routerouteur.use(limiter); // toutes les routes d'un routeurL’ordre de déclaration compte : un middleware s’applique aux routes déclarées après lui.
Middlewares intégrés
Section intitulée « Middlewares intégrés »app.use(express.json({ limit: '100kb' }));app.use(express.urlencoded({ extended: false }));app.use(express.static('public', { maxAge: '1d' }));app.use(express.text()); // text/plainapp.use(express.raw()); // corps binaireLimiter la taille des corps (limit) protège contre l’envoi de requêtes volumineuses.
Middlewares courants
Section intitulée « Middlewares courants »npm install morgan compression cors cookie-parserimport morgan from 'morgan';import compression from 'compression';import cors from 'cors';import cookieParser from 'cookie-parser';
app.use(morgan('combined')); // journal d'accèsapp.use(compression()); // compression des réponsesapp.use(cors({ origin: 'https://exemple.com' }));app.use(cookieParser());| Paquet | Rôle |
|---|---|
morgan |
Journal des requêtes HTTP |
compression |
Compression gzip/deflate (souvent faite par le reverse proxy : éviter le doublon) |
cors |
En-têtes CORS (appels depuis un autre domaine) |
cookie-parser |
Lecture des cookies |
helmet |
En-têtes de sécurité (voir Sécurité et production) |
express-rate-limit |
Limitation du nombre de requêtes |
multer |
Envoi de fichiers (voir Fichiers statiques, envois et vues) |
Authentification par jeton (exemple)
Section intitulée « Authentification par jeton (exemple) »function verifierJeton(req, res, next) { const entete = req.get('Authorization') ?? ''; const [type, jeton] = entete.split(' '); if (type !== 'Bearer' || jeton !== process.env.API_JETON) { return res.status(401).json({ erreur: 'non authentifié' }); } next();}
app.use('/api', verifierJeton);Pour une application réelle, vérifier un jeton signé (JWT) ou une session plutôt qu’une valeur fixe, et comparer les secrets en temps constant (crypto.timingSafeEqual).
Transmettre des données entre middlewares
Section intitulée « Transmettre des données entre middlewares »app.use((req, res, next) => { res.locals.demarreA = Date.now(); req.utilisateur = { id: 1, role: 'admin' }; next();});
app.get('/moi', (req, res) => res.json(req.utilisateur));res.locals sert aussi à passer des données aux vues.
Middleware asynchrone (Express 5)
Section intitulée « Middleware asynchrone (Express 5) »app.use(async (req, res, next) => { req.utilisateur = await chargerUtilisateur(req.get('X-Id')); next();});En Express 5, une erreur levée (ou une promesse rejetée) dans un middleware ou un gestionnaire asynchrone est transmise automatiquement au gestionnaire d’erreurs. Avec Express 4, il fallait attraper l’erreur et appeler next(err).
Gestionnaire d’erreurs
Section intitulée « Gestionnaire d’erreurs »Un gestionnaire d’erreurs a quatre paramètres et se déclare en dernier :
app.use((req, res) => { res.status(404).json({ erreur: 'introuvable' });});
app.use((err, req, res, next) => { console.error(err); if (res.headersSent) return next(err); const statut = err.statut ?? 500; res.status(statut).json({ erreur: statut === 500 ? 'erreur interne' : err.message, });});Ne pas renvoyer err.stack ni le message d’une erreur interne au client : ils révèlent le fonctionnement du serveur.
Erreur volontaire avec un code :
class ErreurHttp extends Error { constructor(statut, message) { super(message); this.statut = statut; }}
app.get('/clients/:id', async (req, res) => { const client = await trouverClient(Number(req.params.id)); if (!client) throw new ErreurHttp(404, 'client introuvable'); res.json(client);});Dépannage
Section intitulée « Dépannage »| Symptôme | Piste |
|---|---|
| La requête ne se termine jamais | Middleware sans next() ni réponse |
| Le middleware n’agit pas sur une route | Déclaré après la route |
Cannot set headers after they are sent |
Réponse envoyée puis next() : utiliser return |
| Le gestionnaire d’erreurs n’est pas appelé | Moins de quatre paramètres : (err, req, res, next) |
| Erreur CORS dans le navigateur | origin non autorisé, ou requête préliminaire (OPTIONS) mal traitée |
Corps tronqué ou PayloadTooLargeError |
Limite limit dépassée |
Ubuntu 24.04 et 26.04 : différences à connaître
Section intitulée « Ubuntu 24.04 et 26.04 : différences à connaître »Aucune : les middlewares dépendent d’Express et de Node.js, pas de la distribution.
Pour aller plus loin
Section intitulée « Pour aller plus loin »- Utiliser les middlewares
- Suite : API JSON