Back

Comment fonctionnent les Middleware dans Node.js

Comment fonctionnent les Middleware dans Node.js

Vous avez vu app.use() disséminé dans les bases de code Express. Vous savez que les middleware se situent entre les requêtes et les réponses. Mais lorsque quelque chose se casse dans cette chaîne—une requête reste en suspens, une erreur disparaît, ou les gestionnaires se déclenchent dans le mauvais ordre—le modèle mental s’effondre.

Cet article explique comment les middleware Node.js fonctionnent réellement : ce qu’ils sont, comment le flux de contrôle traverse la chaîne, et ce qui a changé dans Express 5.

Points clés à retenir

  • Les middleware sont un pattern de framework, pas une fonctionnalité Node.js—Express les implémente au-dessus du module http natif
  • L’ordre d’exécution est important : les middleware s’exécutent dans l’ordre d’enregistrement, et les gestionnaires d’erreurs doivent venir en dernier
  • La fonction next() contrôle le flux ; l’omettre sans envoyer de réponse provoque le blocage des requêtes
  • Express 5 capture nativement les promesses rejetées des middleware asynchrones et des gestionnaires de routes, éliminant le besoin de wrappers manuels

Les Middleware sont un Pattern de Framework, pas une Fonctionnalité Node.js

Node.js lui-même n’a aucun concept de middleware. Le module http natif vous donne un objet request et response—rien de plus. Les middleware sont un pattern que des frameworks comme Express implémentent au-dessus de Node.js.

Les middleware Express suivent une structure spécifique : des fonctions qui reçoivent req, res, et next. Le framework maintient une pile de ces fonctions et les appelle séquentiellement pour chaque requête entrante. Ce cycle de vie des requêtes dans les frameworks Node.js est ce qui donne leur puissance aux middleware.

D’autres frameworks implémentent des patterns similaires différemment. Koa utilise un “modèle d’oignon” où les middleware s’enroulent autour des gestionnaires suivants. Fastify utilise des hooks à des points spécifiques du cycle de vie. Le concept se transfère, mais pas la sémantique.

Le Cycle de Vie Requête-Réponse

Lorsqu’une requête atteint une application Express, elle entre dans un pipeline :

  1. Express fait correspondre la requête avec les middleware et routes enregistrés
  2. Chaque fonction middleware s’exécute dans l’ordre d’enregistrement
  3. Le contrôle passe en avant via next() ou s’arrête lorsqu’une réponse est envoyée
  4. Les middleware de gestion d’erreurs capturent les erreurs passées à next(err) ainsi que les erreurs levées ou rejetées dans les middleware et gestionnaires de routes gérés par Express

La fonction next() est le mécanisme qui fait avancer le contrôle à travers la chaîne. Appelez-la, et Express invoque le prochain middleware correspondant. Omettez-la sans envoyer de réponse, et la requête reste bloquée indéfiniment.

L’Ordre des Middleware est Important

Les middleware Express s’exécutent dans l’ordre où vous les enregistrez. Ce n’est pas juste un détail—c’est le fondement des patterns de middleware dans Node.js.

app.use(parseBody)
app.use(authenticate)
app.use(authorize)
app.get('/data', handler)

Ici, parseBody s’exécute en premier, rendant les données de requête disponibles pour authenticate. Inversez leur ordre, et l’authentification échoue car le corps n’a pas encore été parsé.

Cet ordre affecte également la gestion des erreurs. Les middleware de gestion d’erreurs doivent venir après les routes qu’ils protègent.

Court-Circuiter la Réponse

Les middleware peuvent terminer le cycle requête-réponse prématurément en envoyant une réponse sans appeler next(). C’est ainsi que les middleware d’authentification rejettent les requêtes non autorisées :

function requireAuth(req, res, next) {
  if (!req.user) {
    return res.status(401).json({ error: 'Unauthorized' })
  }
  next()
}

Une fois que res.send(), res.json(), ou des méthodes similaires s’exécutent, les middleware suivants ne s’exécuteront pas pour cette requête. Ce court-circuit est intentionnel et utile.

Middleware au Niveau Application, Router et Route

Les middleware Express s’attachent à différentes portées :

Niveau application : les middleware s’exécutent pour chaque requête vers l’application. Utilisez app.use() pour les préoccupations transversales comme le logging ou le parsing du corps.

Niveau router : les middleware s’exécutent pour les requêtes correspondant à un router spécifique. Cela limite les middleware à des groupes de routes sans affecter toute l’application.

Niveau route : les middleware s’exécutent uniquement pour des routes spécifiques. Passez les fonctions middleware directement aux définitions de routes pour un comportement ciblé comme la validation.

La distinction concerne la portée, pas la capacité. Les trois utilisent la même signature de fonction.

Gestion des Erreurs et Middleware Express 5

Express identifie les middleware de gestion d’erreurs par leur signature à quatre paramètres : (err, req, res, next). Lorsqu’un middleware appelle next(err) ou lève une erreur, Express ignore les middleware réguliers et passe directement aux gestionnaires d’erreurs.

Express 5 change la façon dont les erreurs asynchrones fonctionnent. Dans Express 4, les promesses rejetées et les exceptions asynchrones nécessitaient une gestion manuelle ou des wrappers tiers. Express 5 capture nativement les promesses rejetées des fonctions asynchrones et les route automatiquement vers les gestionnaires d’erreurs.

// Express 5 : pas besoin de wrapper
app.get('/data', async (req, res) => {
  const data = await fetchData() // le rejet déclenche le middleware d'erreur
  res.json(data)
})

app.use((err, req, res, next) => {
  res.status(500).json({ error: err.message })
})

Les middleware de gestion d’erreurs doivent toujours être enregistrés en dernier, après les routes et autres middleware.

Conclusion

Les middleware sont un pattern au niveau framework pour traiter les requêtes à travers une chaîne de fonctions. Comprendre l’ordre d’exécution, le rôle de next(), et où placer les gestionnaires d’erreurs élimine la plupart des problèmes de débogage de middleware.

La gestion native des erreurs asynchrones d’Express 5 supprime un point de friction courant, mais les fondamentaux restent : enregistrez les middleware dans le bon ordre, appelez next() ou envoyez une réponse, et placez les gestionnaires d’erreurs à la fin.

FAQ

Si vous oubliez d'appeler next() et n'envoyez pas de réponse, la requête restera bloquée indéfiniment. Express attend soit que next() soit appelé pour continuer la chaîne, soit qu'une réponse soit envoyée au client. Assurez-vous toujours que votre middleware appelle soit next() pour passer le contrôle en avant, soit envoie une réponse pour terminer le cycle.

Oui, mais vous devez gérer les erreurs manuellement. Express 4 ne capture pas automatiquement les promesses rejetées, donc les rejets non gérés ne déclencheront pas votre middleware de gestion d'erreurs. Enveloppez le code asynchrone dans des blocs try-catch ou utilisez une fonction wrapper qui transmet les erreurs à next(). Express 5 élimine cette exigence en capturant les rejets nativement.

Les middleware de gestion d'erreurs nécessitent exactement quatre paramètres : err, req, res, et next. Si vous omettez un paramètre, Express le traite comme un middleware régulier et l'ignore pendant la gestion des erreurs. Vérifiez également que votre gestionnaire d'erreurs est enregistré après toutes les routes et autres middleware dans votre application.

Les deux enregistrent des middleware avec la même signature de fonction, mais ils diffèrent en portée. app.use() attache les middleware au niveau application, s'exécutant pour toutes les requêtes. router.use() attache les middleware à une instance de router spécifique, s'exécutant uniquement pour les requêtes qui correspondent au chemin monté de ce router.

Gain Debugging Superpowers

Unleash the power of session replay to reproduce bugs, track slowdowns and uncover frustrations in your app. Get complete visibility into your frontend with OpenReplay — the most advanced open-source session replay tool for developers. Check our GitHub repo and join the thousands of developers in our community.

OpenReplay