Mon cas d'utilisation envoie un message d'erreur JSON personnalisé, car j'utilise express pour alimenter mon API REST. Je pense que c'est un scénario assez courant, alors je vais me concentrer sur cela dans ma réponse.
Version courte:
Traitement des erreurs express
Définissez le middleware de gestion des erreurs comme tout autre middleware, sauf avec quatre arguments au lieu de trois, spécifiquement avec la signature (err, req, res, next). ... Vous définissez le middleware de gestion des erreurs en dernier, après les autres app.use () et achemine les appels
app.use(function(err, req, res, next) {
if (err instanceof JSONError) {
res.status(err.status).json({
status: err.status,
message: err.message
});
} else {
next(err);
}
});
Soulevez des erreurs à partir de n'importe quel point du code en faisant:
var JSONError = require('./JSONError');
var err = new JSONError(404, 'Uh oh! Can't find something');
next(err);
Version longue
La manière canonique de lancer des erreurs est:
var err = new Error("Uh oh! Can't find something");
err.status = 404;
next(err)
Par défaut, Express gère cela en l'empaquetant proprement en tant que réponse HTTP avec le code 404 et un corps composé de la chaîne de message ajoutée avec une trace de pile.
Cela ne fonctionne pas pour moi lorsque j'utilise Express comme serveur REST, par exemple. Je veux que l'erreur soit renvoyée en JSON, pas en HTML. Je ne veux certainement pas non plus que ma trace de pile soit transférée vers mon client.
Je peux envoyer JSON comme réponse en utilisant req.json()
, par exemple. quelque chose comme req.json({ status: 404, message: 'Uh oh! Can't find something'})
. En option, je peux définir le code d'état à l'aide de req.status()
. Combiner les deux:
req.status(404).json({ status: 404, message: 'Uh oh! Can't find something'});
Cela fonctionne comme un charme. Cela dit, je trouve qu'il est assez difficile de taper à chaque fois que j'ai une erreur, et le code n'est plus auto-documenté comme le nôtre next(err)
. Cela ressemble beaucoup trop à la façon dont une réponse JSON normale (c'est-à-dire valide) est envoyée. En outre, toutes les erreurs générées par l'approche canonique entraînent toujours une sortie HTML.
C'est là qu'intervient le middleware de gestion des erreurs d'Express. Dans le cadre de mes itinéraires, je définis:
app.use(function(err, req, res, next) {
console.log('Someone tried to throw an error response');
});
Je sous-classe également Error dans une classe JSONError personnalisée:
JSONError = function (status, message) {
Error.prototype.constructor.call(this, status + ': ' + message);
this.status = status;
this.message = message;
};
JSONError.prototype = Object.create(Error);
JSONError.prototype.constructor = JSONError;
Maintenant, quand je veux lancer une erreur dans le code, je fais:
var err = new JSONError(404, 'Uh oh! Can't find something');
next(err);
Pour revenir au middleware de gestion des erreurs personnalisé, je le modifie en:
app.use(function(err, req, res, next) {
if (err instanceof JSONError) {
res.status(err.status).json({
status: err.status,
message: err.message
});
} else {
next(err);
}
}
L'erreur de sous-classification dans JSONError est importante, car je suppose qu'Express instanceof Error
vérifie le premier paramètre passé à a next()
pour déterminer si un gestionnaire normal ou un gestionnaire d'erreurs doit être appelé. Je peux supprimer la instanceof JSONError
vérification et apporter des modifications mineures pour m'assurer que des erreurs inattendues (comme un crash) renvoient également une réponse JSON.