Menu

Middleware Express : comment marche next(), avec exemples

Un middleware Express est une fonction (req, res, next) qui s'exécute avant votre handler de route. Il peut lire ou modifier la requête, y mettre fin avec une réponse, ou appeler next() pour la transmettre.

Cette page contient des éditeurs exécutables. Modifiez, exécutez et voyez la sortie instantanément.

Dans Express, un middleware est une fonction de signature (req, res, next) qui s'exécute entre l'arrivée d'une requête et l'envoi de la réponse. Chaque middleware peut lire ou modifier req et res, terminer la requête en envoyant une réponse, ou appeler next() pour passer la requête à la fonction suivante. app.use(fn) ajoute un middleware pour toutes les requêtes, et Express exécute tout dans l'ordre d'enregistrement.

La Console affiche les trois étapes dans l'ordre pour chaque requête, et la route lit req.startedAt, une propriété ajoutée par le logger. Envoyez GET /missing : les deux middlewares s'affichent quand même, parce que app.use() correspond à tous les chemins, puis Express répond 404 puisqu'aucune route ne correspond.

Oublier next()

Un middleware qui n'envoie pas de réponse et n'appelle pas next() laisse la requête en suspens. Le client attend jusqu'au timeout et rien n'apparaît dans les logs, ce qui en fait un bug de middleware courant. Supprimez next(); du logger ci-dessus et renvoyez GET / : la requête ne reçoit jamais de réponse.

La règle est simple : chaque chemin dans un middleware se termine par exactement une de ces actions :

  • next() pour continuer,
  • next(err) pour sauter au gestionnaire d'erreurs (voir la gestion des erreurs Express),
  • une réponse comme res.json() ou res.status(401).send().

Appeler next() après avoir envoyé une réponse est aussi un bug. Le handler suivant essaie d'envoyer une deuxième réponse et Express lève ERR_HTTP_HEADERS_SENT. Écrivez return res.status(401).json(...) pour que la fonction s'arrête là.

Un contrôle d'accès qui arrête la requête

Un middleware qui rejette une requête envoie lui-même la réponse et n'appelle jamais next(). Passez-le en argument supplémentaire d'une route pour ne protéger que cette route :

La première requête reçoit 401 avec {"error":"Missing or wrong API key"}. Ajoutez l'en-tête x-api-key: secret123 dans la barre de requête et renvoyez-la : la réponse est maintenant {"users":42,"caller":"reporting-app"}. /public n'exécute jamais le contrôle.

Où s'exécute un middleware

Vous écrivezS'exécute pour
app.use(fn)Toutes les requêtes, toutes les méthodes
app.use('/api', fn)Les chemins qui commencent par /api
app.get('/admin', fn, handler)GET /admin seulement, avant handler
router.use(fn)Toutes les routes de ce router

L'ordre fait partie du sens. Un logger enregistré après les routes ne journalise jamais les requêtes auxquelles ces routes ont répondu, car une route qui envoie une réponse n'appelle pas next(). Enregistrez d'abord les middlewares globaux comme le logging, le parsing du corps et CORS, puis les routes, puis les handlers 404 et d'erreurs.

Les middlewares intégrés

Express fournit quelques middlewares que vous ajoutez avec app.use(). Les parsers de corps remplissent req.body ; sans eux, il vaut undefined.

MiddlewareRôle
express.json()Parse les corps JSON (Content-Type: application/json)
express.urlencoded()Parse les envois de formulaires HTML (name=Ada&age=36)
express.text()Met un corps en texte brut dans req.body sous forme de chaîne
express.static('public')Sert les fichiers d'un dossier

Envoyez POST /echo avec le corps {"name": "Ada"} et la réponse contient "body":{"name":"Ada"}. Supprimez la ligne express.json(), renvoyez la requête, et body disparaît de la réponse : req.body vaut undefined, et JSON.stringify omet les valeurs undefined. Des packages comme cors, helmet et morgan sont aussi des middlewares : vous les installez avec npm install et les passez à app.use() de la même façon. La page sur express.static explique comment servir des fichiers.

Erreurs fréquentes

Appeler le middleware au lieu de le passer. app.use(logger()) exécute logger une seule fois au démarrage et enregistre sa valeur de retour. Écrivez app.use(logger). (express.json() a des parenthèses parce qu'il renvoie une fonction middleware.)

Ajouter le parser de corps après les routes. Les routes s'exécutent d'abord et voient req.body à undefined.

S'attendre à ce que app.use('/admin', fn) corresponde à un seul chemin. Il s'exécute aussi pour /admin/users et tous les autres chemins sous /admin, pour toutes les méthodes. Pour protéger une seule route, passez le middleware à app.get('/admin', fn, handler).

Questions fréquentes

Quelle différence entre un middleware et un handler de route ?

Techniquement aucune : ce sont deux fonctions (req, res, next). Par convention, un handler de route termine la requête avec une réponse, alors qu'un middleware fait en général un travail commun et appelle next().

Un middleware peut-il être async ?

Oui. Dans Express 5, un middleware async qui lève une erreur ou renvoie une promesse rejetée transmet automatiquement l'erreur à votre gestionnaire d'erreurs. Attendez avec await ce dont vous avez besoin, puis appelez next().

Que fait next('route') ?

Il saute les handlers restants de la route en cours et passe à la route suivante qui correspond. Il ne fonctionne que dans les handlers ajoutés avec app.get(), app.post() et les autres fonctions de méthode, pas dans app.use().

Comment ignorer un middleware pour une seule route ?

Enregistrez cette route avant le middleware, pour qu'elle réponde en premier, ou vérifiez le chemin dans le middleware (if (req.path === '/health') return next();). Appliquer le middleware par router ou par route plutôt qu'à toute l'application évite souvent le problème.

Illustration des langages de programmation de Coddy

Apprendre à coder avec Coddy

Commencer