Принципы обработки ошибок для приложений Node.js + Express.js?
Похоже, что сообщение об ошибках/обработка ошибок выполняется по-разному в приложениях Node.js + Express.js по сравнению с другими платформами. Правильно ли я понимаю, что он работает следующим образом?
A) Обнаружение ошибок путем их приема в качестве параметров функций обратного вызова. Например:
doSomethingAndRunCallback(function(err) {
if(err) { … }
});
B) Сообщить об ошибках в MIDDLEWARE, вызвав следующую (err). Пример:
handleRequest(req, res, next) {
// An error occurs…
next(err);
}
C) Сообщить об ошибках в МАРШРУТАх, выбросив ошибку. Пример:
app.get('/home', function(req, res) {
// An error occurs
throw err;
});
D) Обработать ошибки, настроив собственный обработчик ошибок с помощью app.error() или использовать общий обработчик ошибок Connect. Пример:
app.error(function(err, req, res, next) {
console.error(err);
res.send('Fail Whale, yo.');
});
Являются ли эти четыре принципа основой для обработки и отчетности ошибок в приложениях Node.js + Express.js?
Ответы
Ответ 1
Обработка ошибок в Node.js обычно имеет формат A). Большинство обратных вызовов возвращают объект ошибки в качестве первого аргумента или null
.
Express.js использует промежуточное программное обеспечение, а синтаксис промежуточного программного обеспечения использует B) и E) (см. ниже).
C) - это плохая практика, если вы спросите меня.
app.get('/home', function(req, res) {
// An error occurs
throw err;
});
Вы можете легко переписать выше, как
app.get('/home', function(req, res, next) {
// An error occurs
next(err);
});
Синтаксис промежуточного программного обеспечения действителен в запросе get
.
Что касается D)
(07:26:37 PM) tjholowaychuk: app.error удаляется в 3.x
TJ только что подтвердил, что app.error
устарел в пользу E
Е)
app.use(function(err, req, res, next) {
// Only handle `next(err)` calls
});
Любое промежуточное ПО, которое имеет длину 4 (4 аргумента), считается промежуточным программным обеспечением ошибок. Когда вы вызываете next(err)
, соединение идет и вызывает связующее ПО на основе ошибок.
Ответ 2
Люди в Joyent опубликовали действительно проницательный документ лучших практик. Обязательно прочитайте статью для любого разработчика Node.js.
Ответ 3
Почему первый параметр?
Из-за асинхронного характера Node.js шаблон с первым параметром-как-err стал хорошо установленным как соглашение для userland Node.js обработки ошибок. Это происходит из-за асинхронности:
try {
setTimeout(function() {
throw 'something broke' //Some random error
}, 5)
}
catch(e) {
//Will never get caught
}
Таким образом, вместо этого первый аргумент обратного вызова - это в значительной степени единственный разумный способ пропускать ошибки асинхронно, а не просто бросать их.
Для этого в результате будет unhandled exception
, который, как это звучит, подразумевает, что ничего не сделано, чтобы заставить приложение выйти из его запутанного состояния.
Исключения, почему они существуют
Однако стоит отметить, что практически все части Node.js являются событиями-эмиттерами, а выброс исключения - это событие низкого уровня, которое можно обрабатывать, как и все события:
//This won't immediately crash if connection fails
var socket = require("net").createConnection(5000);
socket.on("error", function(err) {
console.error("calm down...", err)
});
Этот can-but-shouldn't доведен до крайности уловить все ошибки и сделать заявку который будет очень стараться, чтобы никогда не рухнуть. Это ужасная идея почти в каждом случае использования, потому что она оставит разработчика без каких-либо представлений о том, что происходит в состоянии приложения, и аналогично обертыванию main в try-catch.
Домены - логически группируются события
В рамках решения этой проблемы исключения приложений, которые относятся к приложениям, домены позволяют разработчику взять, например приложение Express.js, и попытаться закрыть контакты разумно в случае катастрофического отказа.
ES6
Вероятно, это говорит о том, что это снова изменится, поскольку ES6 позволяет шаблону генератора создавать асинхронные события, которые все еще захватывают блоки try/catch.
Koa (написанный TJ Holowaychuck, тем же оригинальным автором Express.js) заметно делает это. Он использует инструкцию ES6 yield
для создания блоков, которые, будучи почти синхронными, обрабатываются обычным асинхронным способом node:
app.use(function *(next) {
try {
yield next;
}
catch (err) {
this.status = err.status || 500;
this.body = err.message;
this.app.emit('error', err, this);
}
});
app.use(function *(next) {
throw new Error('some error');
})
Этот пример был бесстыдно украден из здесь.