Skip to content

Gestion des Erreurs dans Express.js

La gestion des erreurs est un élément crucial dans toute application Express. Express utilise un mécanisme de middleware pour gérer à la fois le flux de requête/réponse normal et les erreurs. Les middlewares d'erreur sont définis de la même manière que les autres middlewares, sauf qu'ils ont quatre arguments au lieu de trois : (err, req, res, next).

Création du Projet

sh
mkdir gestionErreurMiddleware
cd gestionErreurMiddleware
npm init -y
npm install express
mkdir gestionErreurMiddleware
cd gestionErreurMiddleware
npm init -y
npm install express

Créez ensuite un fichier app.js.

Création d'un Middleware d'Erreur

Dans votre fichier app.js, vous pouvez créer un middleware d'erreur simple.

javascript
import express from 'express';

const app = express();
app.use(express.json());

// Middleware standard
app.use((req, res, next) => {
  console.log('Middleware standard exécuté!');
  next();
});

// Route qui déclenche une erreur
app.get('/erreur', (req, res, next) => {
  const err = new Error('Erreur délibérée!');
  next(err);
});

// Middleware d'erreur
app.use((err, req, res, next) => {
  console.error(`Erreur capturée: ${err.message}`);
  res.status(500).send('Quelque chose a mal tourné!');
});

const PORT = 3000;
app.listen(PORT, () => {
  console.log(`Serveur écoutant sur le port ${PORT}`);
});
import express from 'express';

const app = express();
app.use(express.json());

// Middleware standard
app.use((req, res, next) => {
  console.log('Middleware standard exécuté!');
  next();
});

// Route qui déclenche une erreur
app.get('/erreur', (req, res, next) => {
  const err = new Error('Erreur délibérée!');
  next(err);
});

// Middleware d'erreur
app.use((err, req, res, next) => {
  console.error(`Erreur capturée: ${err.message}`);
  res.status(500).send('Quelque chose a mal tourné!');
});

const PORT = 3000;
app.listen(PORT, () => {
  console.log(`Serveur écoutant sur le port ${PORT}`);
});

Explication

Dans cet exemple, si un utilisateur accède à la route /erreur, une erreur est créée et passée à next(), indiquant à Express de passer directement au middleware d'erreur, en sautant tous les middlewares intermédiaires restants.

Le middleware d'erreur capture et gère toutes les erreurs qui se produisent dans l'application, qu'elles soient déclenchées explicitement dans les routes ou les middlewares, ou qu'elles résultent d'erreurs d'exécution.

Personnaliser la Réponse d'Erreur

Vous pouvez également personnaliser vos réponses d'erreur en fonction du type d'erreur reçu ou même de l'environnement de l'application, pour éviter d'exposer des détails d'erreur sensibles en production.

javascript
app.use((err, req, res, next) => {
  console.error(`Erreur capturée: ${err.message}`);
  
  if (app.get('env') === 'development') {
    return res.status(500).json({ error: err.message, stack: err.stack });
  }

  res.status(500).send('Quelque chose a mal tourné!');
});
app.use((err, req, res, next) => {
  console.error(`Erreur capturée: ${err.message}`);
  
  if (app.get('env') === 'development') {
    return res.status(500).json({ error: err.message, stack: err.stack });
  }

  res.status(500).send('Quelque chose a mal tourné!');
});

Dans cet exemple, si l'application est en mode développement, le middleware d'erreur renvoie à la fois le message d'erreur et la pile d'appels (stack trace) au client. En mode production, seul un message d'erreur générique est renvoyé.

Bonnes pratiques

1. Limiter les Informations Exposées: En mode production, ne renvoyez jamais les détails internes de l'erreur (comme les stack traces) aux clients. Ces informations peuvent être exploitées par des attaquants pour comprendre la structure et les vulnérabilités de votre application. Il est recommandé de loguer les détails de l'erreur côté serveur, mais de ne renvoyer qu'un message d'erreur générique au client, par exemple :

javascript
res.status(500).send('Une erreur interne est survenue, veuillez réessayer plus tard.');
res.status(500).send('Une erreur interne est survenue, veuillez réessayer plus tard.');

2. Logging des Erreurs: Loguez systématiquement les erreurs côté serveur, de manière à pouvoir diagnostiquer et résoudre les problèmes rapidement. Utilisez des outils et services de logging appropriés qui permettent d'organiser, de filtrer et d'analyser les logs efficacement.

3. Monitoring et Alerte: Mettez en place des systèmes de monitoring et d'alerte pour être informé immédiatement lorsqu'une erreur se produit en production. Cela permet une réaction et une résolution rapides, minimisant ainsi le temps de downtime et l'impact sur les utilisateurs.

4. Environnement de Développement Séparé: Maintenez des environnements de développement, de test et de production séparés avec des configurations appropriées pour chaque environnement. Par exemple, en développement, vous pouvez exposer plus d'informations sur les erreurs pour faciliter le débogage.

5. Sécurisation des Données Sensibles: Veillez à ne jamais exposer de données sensibles telles que des mots de passe, des clés API, ou des informations personnelles des utilisateurs dans les messages d'erreur.

6. Tests: Effectuez des tests réguliers, y compris des tests d'erreur, pour vous assurer que votre application gère correctement les erreurs et ne divulgue pas d'informations sensibles.

7. Mises à jour et Patches: Gardez votre application, vos dépendances et votre système d'exploitation à jour avec les derniers patches de sécurité.

Tester l'Application

Pour tester l'application, lancez votre serveur avec node app.js et utilisez un outil comme Postman ou cURL pour envoyer une requête GET à http://localhost:3000/erreur.

Vous devriez voir le message d'erreur dans la console où votre serveur s'exécute, et vous recevrez une réponse HTTP 500 avec le message d'erreur correspondant en fonction de votre environnement d'exécution.

Code en entier

javascript
import express from 'express';

const app = express(); // Crée une instance d'application Express

app.use(express.json()); // Middleware intégré pour parser le corps des requêtes JSON

// Middleware standard qui s'exécute pour toutes les requêtes
app.use((req, res, next) => {
  console.log('Middleware standard exécuté!');
  next(); // Passe au prochain middleware
});

// Route qui déclenche une erreur
app.get('/erreur', (req, res, next) => {
  const err = new Error('Erreur délibérée!'); // Crée une nouvelle erreur
  next(err); // Passe l'erreur au prochain middleware d'erreur
});

// Route normale pour comparer
app.get('/', (req, res) => {
  res.send('Tout va bien ici!');
});

// Middleware d'erreur pour gérer toutes les erreurs
app.use((err, req, res, next) => {
  console.error(`Erreur capturée: ${err.message}`); // Log l'erreur à la console
  // Personnalise la réponse en fonction de l'environnement
  if (app.get('env') === 'development') {
    res.status(500).json({ error: err.message, stack: err.stack }); // Renvoie le message d'erreur et la stack trace
  } else {
    res.status(500).send('Quelque chose a mal tourné!'); // Renvoie un message d'erreur générique
  }
});

// Démarre le serveur sur le port 3000
const PORT = 3000;
app.listen(PORT, () => {
  console.log(`Serveur écoutant sur le port ${PORT}`);
});
import express from 'express';

const app = express(); // Crée une instance d'application Express

app.use(express.json()); // Middleware intégré pour parser le corps des requêtes JSON

// Middleware standard qui s'exécute pour toutes les requêtes
app.use((req, res, next) => {
  console.log('Middleware standard exécuté!');
  next(); // Passe au prochain middleware
});

// Route qui déclenche une erreur
app.get('/erreur', (req, res, next) => {
  const err = new Error('Erreur délibérée!'); // Crée une nouvelle erreur
  next(err); // Passe l'erreur au prochain middleware d'erreur
});

// Route normale pour comparer
app.get('/', (req, res) => {
  res.send('Tout va bien ici!');
});

// Middleware d'erreur pour gérer toutes les erreurs
app.use((err, req, res, next) => {
  console.error(`Erreur capturée: ${err.message}`); // Log l'erreur à la console
  // Personnalise la réponse en fonction de l'environnement
  if (app.get('env') === 'development') {
    res.status(500).json({ error: err.message, stack: err.stack }); // Renvoie le message d'erreur et la stack trace
  } else {
    res.status(500).send('Quelque chose a mal tourné!'); // Renvoie un message d'erreur générique
  }
});

// Démarre le serveur sur le port 3000
const PORT = 3000;
app.listen(PORT, () => {
  console.log(`Serveur écoutant sur le port ${PORT}`);
});