Без специального выделенного объекта для обработки ошибок больше шансов на то, что важные ошибки скрываются под радаром из-за неправильного обращения. Объект обработчика ошибок отвечает за отображение ошибки, например, путем записи в хорошо отформатированный регистратор, отправки событий в некоторые продукты мониторинга, такие как Sentry, Rollbar или Raygun. Большинство веб-фреймворков, таких как Express, предоставляют механизм промежуточного программного обеспечения для обработки ошибок. Типичный поток обработки ошибок может быть следующим: какой-то модуль выдает ошибку -> маршрутизатор API перехватывает ошибку -> он передает ошибку промежуточному программному обеспечению (например, Express, KOA), которое отвечает за перехват ошибок -> вызывается централизованный обработчик ошибок -> промежуточному программному обеспечению сообщается, является ли эта ошибка ненадежной (не работающей), чтобы она могла корректно перезапустить приложение. Обратите внимание, что обычная, но неправильная практика - обрабатывать ошибки в промежуточном программном обеспечении Express - это не распространяется на ошибки, возникающие в не-веб-интерфейсах.
Javascript
// DAL layer, we don't handle errors here
DB.addDocument(newCustomer, (error, result) => {
if (error)
throw new Error('Great error explanation comes here', other useful parameters)
});
// API route code, we catch both sync and async errors and forward to the middleware
try {
customerService.addNew(req.body).then((result) => {
res.status(200).json(result);
}).catch((error) => {
next(error)
});
}
catch (error) {
next(error);
}
// Error handling middleware, we delegate the handling to the centralized error handler
app.use(async (err, req, res, next) => {
const isOperationalError = await errorHandler.handleError(err);
if (!isOperationalError) {
next(err);
}
});
Typescript
// DAL layer, we don't handle errors here
DB.addDocument(newCustomer, (error: Error, result: Result) => {
if (error)
throw new Error('Great error explanation comes here', other useful parameters)
});
// API route code, we catch both sync and async errors and forward to the middleware
try {
customerService.addNew(req.body).then((result: Result) => {
res.status(200).json(result);
}).catch((error: Error) => {
next(error)
});
}
catch (error) {
next(error);
}
// Error handling middleware, we delegate the handling to the centralized error handler
app.use(async (err: Error, req: Request, res: Response, next: NextFunction) => {
const isOperationalError = await errorHandler.handleError(err);
if (!isOperationalError) {
next(err);
}
});
Javascript
module.exports.handler = new errorHandler();
function errorHandler() {
this.handleError = async (err) {
await logger.logError(err);
await sendMailToAdminIfCritical;
await saveInOpsQueueIfCritical;
await determineIfOperationalError;
};
}
Typescript
class ErrorHandler {
public async handleError(err: Error): Promise<void> {
await logger.logError(err);
await sendMailToAdminIfCritical();
await saveInOpsQueueIfCritical();
await determineIfOperationalError();
};
}
export const handler = new ErrorHandler();
Javascript
// middleware handling the error directly, who will handle Cron jobs and testing errors?
app.use((err, req, res, next) => {
logger.logError(err);
if (err.severity == errors.high) {
mailer.sendMail(configuration.adminMail, 'Critical error occured', err);
}
if (!err.isOperational) {
next(err);
}
});
Typescript
// middleware handling the error directly, who will handle Cron jobs and testing errors?
app.use((err: Error, req: Request, res: Response, next: NextFunction) => {
logger.logError(err);
if (err.severity == errors.high) {
mailer.sendMail(configuration.adminMail, 'Critical error occured', err);
}
if (!err.isOperational) {
next(err);
}
});
Цитата из блога: "Иногда нижние уровни не могут сделать ничего полезного, кроме как сообщить об ошибке вызывающей стороне"
Из блога Joyent, занимающий 1 место по ключевым словам "Обработка ошибок Node.js"
… Вы можете обработать одну и ту же ошибку на нескольких уровнях стека. Это происходит, когда нижние уровни не могут сделать ничего полезного, кроме как передать ошибку вызывающей стороне, которая передает ошибку своей вызывающей стороне, и так далее. Зачастую только вызывающий пользователь верхнего уровня знает, что является подходящим ответом: попытка повторить операцию, сообщить пользователю об ошибке или что-то еще. Но это не значит, что вы должны пытаться сообщать обо всех ошибках в один обратный вызов верхнего уровня, потому что сам этот обратный вызов не может знать, в каком контексте произошла ошибка …
Из блога JS Recipes, занимающий 17 место по ключевым словам "Обработка ошибок Node.js"
… Только в контроллере api.js Hackathon Starter имеется более 79 случаев появления объектов ошибок. Обработка каждой ошибки в отдельности привела бы к огромному количеству дублирования кода. Следующее, что вы можете сделать, это делегировать всю логику обработки ошибок в промежуточное ПО Express …
Из блога Daily JS, занимающем 14 место по ключевым словам "Обработка ошибок Node.js"
… Вы должны установить полезные свойства в объектах ошибок, но использовать их последовательно. И не пересекайте потоки: в коде вашей базы данных нет места ошибкам HTTP. Или для разработчиков браузеров, ошибки Ajax имеют место в коде, который общается с сервером, но не в коде, который обрабатывает шаблоны усов …