web-dev-qa-db-fra.com

Comment gérer correctement les erreurs dans Express?

Je commence à travailler avec Express JS et j'ai rencontré un problème. Je n'arrive pas à comprendre la bonne façon de gérer les erreurs.

Par exemple, j'ai une API de services Web qui sert un objet appelé "événement". Je voudrais renvoyer une simple chaîne "ne peut pas trouver d'événement" lorsqu'un utilisateur soumet un ID d'événement qui n'est pas trouvé. Voici comment je structure actuellement mon code:

app.get('/event/:id', function(req, res, next) {
    if (req.params.id != 1) {
        next(new Error('cannot find event ' + req.params.id));
    }

    req.send('event found!');
});

Lorsque je soumets un id autre que 1, Node se bloque avec la sortie suivante:

http.js:527
   throw new Error("Can't set headers after they are sent.");
         ^
Error: Can't set headers after they are sent.
    at ServerResponse.<anonymous> (http.js:527:11)
    at ServerResponse.setHeader (/usr/local/kayak/node_modules/express/node_modules/connect/lib/patch.js:62:20)
    at /usr/local/kayak/node_modules/express/node_modules/connect/lib/middleware/errorHandler.js:72:19
    at [object Object].<anonymous> (fs.js:107:5)
    at [object Object].emit (events.js:61:17)
    at afterRead (fs.js:878:12)
    at wrapper (fs.js:245:17)

D'après ce que je peux dire en utilisant le débogueur node.js , l'exécution du bloc de code se poursuit après l'appel de next(), ce qui signifie que req.send('event found!') essaie d'exécuter. Je ne veux pas que cela se produise.

La seule solution de contournement que j'ai trouvée consiste à simplement lancer une new Error() au lieu de la "suivre", mais cela entraîne la génération d'une page d'erreur HTML Express par défaut. J'aimerais un peu plus de contrôle que ça.

J'ai pris le temps de relire la section de gestion des erreurs de la documentation Express, mais je ne pouvais pas la comprendre.

24
YWCA Hello

Vous aurez envie de vérifier Express Error Handling . De là:

app.param('userId', function(req, res, next, id) {
    User.get(id, function(err, user) {
        if (err) return next(err);
        if (!user) return next(new Error('failed to find user'));
        req.user = user;
        next();
    });
});

Le sweetspot qui vous manque est le returnnext(...)

35
Chance

C'est parce que vous vous trompez: vous avez déjà jeté une erreur (qui sera traitée par Express et retourner une page d'erreur 500 pour l'utilisateur ou quelque chose comme ça) mais vous essayez également d'envoyer votre propre réponse au client: res.send ('événement trouvé!');

Vous devriez vraiment consulter le guide Express sur la gestion des erreurs ici: http://expressjs.com/guide/error-handling.html

Ce que je ferais dans votre exemple, c'est:

function NotFound(msg){
  this.name = 'NotFound';
  Error.call(this, msg);
  Error.captureStackTrace(this, arguments.callee);
} 

app.get('/event/:id', function(req, res, next){
  if (req.params.id != 1) {
    throw new NotFound('Cannot find event ' + req.params.id);
  } else {
    res.send('event found!');
  }
});

app.error(function(err, req, res, next){
    if (err instanceof NotFound) {
        res.render('404.ejs');
    } else {
        next(err);
    }
});
19
alessioalex

Vous avez quelques problèmes avec votre code:

  • Lorsque vous répondez au client, vous devez utiliser l'objet response (res plutôt que req).

  • Lorsque vous envoyez une erreur à next, vous devez return, donc le reste de la fonction ne fonctionne pas courir.

Voici votre code après avoir corrigé ces erreurs:

app.get('/event/:id', function(req, res, next) {
    if (req.params.id != 1) {
        return next(new Error('cannot find event ' + req.params.id));
    }

    res.send('event found!'); // use res.send (NOT req.send)
}); 
10
evilcelery