Mein Anwendungsfall ist das Senden einer benutzerdefinierten JSON-Fehlermeldung, da ich Express verwende, um meine REST-API mit Strom zu versorgen. Ich denke, dies ist ein ziemlich häufiges Szenario, daher werde ich mich in meiner Antwort darauf konzentrieren.
Kurzfassung:
Express-Fehlerbehandlung
Definieren Sie Middleware zur Fehlerbehandlung wie andere Middleware, außer mit vier statt drei Argumenten, insbesondere mit der Signatur (err, req, res, next). ... Sie definieren die Middleware zur Fehlerbehandlung zuletzt nach anderen app.use () - und leiten Anrufe weiter
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);
}
});
Erhöhen Sie Fehler an einer beliebigen Stelle im Code, indem Sie Folgendes tun:
var JSONError = require('./JSONError');
var err = new JSONError(404, 'Uh oh! Can't find something');
next(err);
Lange Version
Die kanonische Art, Fehler zu werfen, ist:
var err = new Error("Uh oh! Can't find something");
err.status = 404;
next(err)
Standardmäßig behandelt Express dies, indem es es ordentlich als HTTP-Antwort mit Code 404 verpackt und einen Text enthält, der aus der Nachrichtenzeichenfolge besteht, an die ein Stack-Trace angehängt ist.
Dies funktioniert bei mir nicht, wenn ich beispielsweise Express als REST-Server verwende. Ich möchte, dass der Fehler als JSON und nicht als HTML zurückgesendet wird. Ich möchte auch definitiv nicht, dass mein Stack-Trace auf meinen Client übertragen wird.
Ich kann JSON als Antwort senden req.json()
, z. so etwas wie req.json({ status: 404, message: 'Uh oh! Can't find something'})
. Optional kann ich den Statuscode mit einstellen req.status()
. Kombination der beiden:
req.status(404).json({ status: 404, message: 'Uh oh! Can't find something'});
Das funktioniert wie ein Zauber. Trotzdem finde ich es ziemlich unhandlich, jedes Mal zu tippen, wenn ich einen Fehler habe, und der Code ist nicht mehr so selbstdokumentierend wie unser Code next(err)
. Es sieht viel zu ähnlich aus, wie eine normale (dh gültige) Antwort JSON gesendet wird. Darüber hinaus führen alle Fehler, die durch den kanonischen Ansatz ausgelöst werden, immer noch zu einer HTML-Ausgabe.
Hier kommt die Fehlerbehandlungs-Middleware von Express ins Spiel. Als Teil meiner Routen definiere ich:
app.use(function(err, req, res, next) {
console.log('Someone tried to throw an error response');
});
Ich habe auch Fehler in eine benutzerdefinierte JSONError-Klasse unterteilt:
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;
Wenn ich jetzt einen Fehler in den Code werfen möchte, mache ich:
var err = new JSONError(404, 'Uh oh! Can't find something');
next(err);
Zurück zur benutzerdefinierten Middleware zur Fehlerbehandlung ändere ich sie wie folgt:
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);
}
}
Das Unterklassifizieren von Fehlern in JSONError ist wichtig, da Express vermutlich instanceof Error
den ersten an a übergebenen Parameter überprüft, next()
um festzustellen, ob ein normaler Handler oder ein Fehlerhandler aufgerufen werden muss. Ich kann die instanceof JSONError
Prüfung entfernen und geringfügige Änderungen vornehmen, um sicherzustellen, dass unerwartete Fehler (z. B. ein Absturz) auch eine JSON-Antwort zurückgeben.