Мій варіант використання надсилає власне повідомлення про помилку JSON, оскільки я використовую express для живлення мого REST API. Я думаю, що це досить поширений сценарій, тому зосередимось на цьому у своїй відповіді.
Коротка версія:
Експрес-обробка помилок
Визначте проміжне програмне забезпечення для обробки помилок, як інше проміжне програмне забезпечення, за винятком чотирьох аргументів замість трьох, зокрема підписом (err, req, res, next). ... Ви визначаєте обробку помилок проміжне програмне забезпечення останнє, після іншого app.use () та маршрутизує виклики
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);
}
});
Піднімайте помилки з будь-якої точки коду, виконуючи:
var JSONError = require('./JSONError');
var err = new JSONError(404, 'Uh oh! Can't find something');
next(err);
Довга версія
Канонічним способом помилок метання є:
var err = new Error("Uh oh! Can't find something");
err.status = 404;
next(err)
За замовчуванням Express обробляє це, акуратно упаковуючи його як відповідь HTTP з кодом 404 та тіло, що складається з рядка повідомлення, доданого із трасуванням стека.
Наприклад, це не працює для мене, коли я використовую Express як REST-сервер. Я хочу, щоб помилка була надіслана назад як JSON, а не як HTML. Я також точно не хочу, щоб мій стек переміщувався до мого клієнта.
Я можу надіслати JSON як відповідь, використовуючи req.json()
, наприклад. щось на зразок req.json({ status: 404, message: 'Uh oh! Can't find something'})
. За бажанням я можу встановити код стану за допомогою req.status()
. Поєднуючи два:
req.status(404).json({ status: 404, message: 'Uh oh! Can't find something'});
Це працює як шарм. Тим не менш, я вважаю, що це досить громіздко друкувати кожного разу, коли у мене виникає помилка, і код більше не самодокументовується, як у нас next(err)
. Це виглядає занадто схожим на те, як надсилається звичайна (тобто діюча) відповідь JSON. Крім того, будь-які помилки, спричинені канонічним підходом, все одно призводять до виводу HTML.
Тут виникає помилка Express щодо обробки проміжного програмного забезпечення. В рамках своїх маршрутів я визначаю:
app.use(function(err, req, res, next) {
console.log('Someone tried to throw an error response');
});
Я також підкласую помилку до спеціального класу 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;
Тепер, коли я хочу вивести помилку в коді, я роблю:
var err = new JSONError(404, 'Uh oh! Can't find something');
next(err);
Повертаючись до власної помилки, яка обробляє проміжне програмне забезпечення, я змінюю її на:
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);
}
}
Підкласифікація помилки в JSONError є важливою, оскільки я підозрюю, що Express здійснює instanceof Error
перевірку першого параметра, переданого в a, next()
щоб визначити, чи потрібно викликати звичайний обробник або обробник помилок. Я можу зняти instanceof JSONError
чек і внести незначні зміни, щоб забезпечити несподівані помилки (наприклад, збій), а також повернути відповідь JSON.