Mój przypadek użycia wysyła niestandardowy komunikat o błędzie JSON, ponieważ używam ekspresu do zasilania mojego interfejsu API REST. Myślę, że jest to dość powszechny scenariusz, więc skupię się na tym w mojej odpowiedzi.
Krótka wersja:
Ekspresowa obsługa błędów
Zdefiniuj oprogramowanie pośredniczące do obsługi błędów, podobnie jak inne oprogramowanie pośredniczące, z wyjątkiem czterech argumentów zamiast trzech, w szczególności z sygnaturą (err, req, res, next). ... Oprogramowanie pośredniczące do obsługi błędów definiuje się jako ostatnie, po innych app.use () i kieruje wywołania
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);
}
});
Podnieś błędy z dowolnego miejsca w kodzie, wykonując:
var JSONError = require('./JSONError');
var err = new JSONError(404, 'Uh oh! Can't find something');
next(err);
Długa wersja
Kanoniczny sposób zgłaszania błędów to:
var err = new Error("Uh oh! Can't find something");
err.status = 404;
next(err)
Domyślnie Express obsługuje to, starannie pakując je jako odpowiedź HTTP z kodem 404 i treścią składającą się z ciągu komunikatu dołączonego do śladu stosu.
Na przykład to nie działa, gdy używam Express jako serwera REST. Chcę, aby błąd został odesłany w formacie JSON, a nie HTML. Zdecydowanie nie chcę też, aby mój ślad stosu został przeniesiony do mojego klienta.
Mogę wysłać JSON jako odpowiedź używając req.json()np. coś w stylu req.json({ status: 404, message: 'Uh oh! Can't find something'}). Opcjonalnie mogę ustawić kod statusu za pomocą req.status(). Połączenie tych dwóch:
req.status(404).json({ status: 404, message: 'Uh oh! Can't find something'});
To działa jak urok. To powiedziawszy, uważam, że pisanie za każdym razem, gdy mam błąd, jest dość nieporęczne, a kod nie dokumentuje się już samoczynnie, jak nasz next(err). Wygląda to zbyt podobnie do wysyłania normalnej (tj. Prawidłowej) odpowiedzi w formacie JSON. Co więcej, wszelkie błędy zgłaszane przez podejście kanoniczne nadal skutkują wynikiem w postaci HTML.
W tym miejscu pojawia się oprogramowanie pośredniczące do obsługi błędów Express. W ramach moich tras definiuję:
app.use(function(err, req, res, next) {
console.log('Someone tried to throw an error response');
});
Podklasuję również Error do niestandardowej klasy JSONError:
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;
Teraz, gdy chcę zgłosić błąd w kodzie, robię:
var err = new JSONError(404, 'Uh oh! Can't find something');
next(err);
Wracając do niestandardowego oprogramowania pośredniczącego do obsługi błędów, modyfikuję je, aby:
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);
}
}
Podklasowanie błędu do JSONError jest ważne, ponieważ podejrzewam, że Express instanceof Errorsprawdza pierwszy parametr przekazany do a, next()aby określić, czy należy wywołać normalną procedurę obsługi lub procedurę obsługi błędów. Mogę usunąć instanceof JSONErrorczek i wprowadzić drobne modyfikacje, aby zapewnić, że nieoczekiwane błędy (takie jak awaria) również zwrócą odpowiedź JSON.