Как обрабатывать исключения кода в node.js?
Я просмотрел документацию Express, и часть, описывающая обработку ошибок, полностью непрозрачна для меня.
Я понял, что app
они имеют в виду экземпляр createServer()
, правильно? Но я не знаю, как остановить node.js от раздувания процесса приложения, когда во время обработки запроса возникает исключение.
Мне действительно ничего не нужно; Я просто хочу вернуть статус 500, плюс пустой ответ, когда есть исключение. Процесс node не должен завершаться только потому, что где-то было неотображенное исключение.
Есть ли простой пример того, как достичь этого?
var express = require('express');
var http = require('http');
var app = express.createServer();
app.get('/', function(req, res){
console.log("debug", "calling")
var options = {
host: 'www.google.com',
port: 80,
path: "/"
};
http.get(options, function(response) {
response.on("data", function(chunk) {
console.log("data: " + chunk);
chunk.call(); // no such method; throws here
});
}).on('error', function(e) {
console.log("error connecting" + e.message);
});
});
app.configure(function(){
app.use(express.errorHandler({ dumpExceptions: true, showStack: true }));
});
app.listen(3000);
сбой всего приложения, создание трассировки
mypath/tst.js:16
chunk.call(); // no such method; throws here
^ TypeError: Object ... has no method 'call'
at IncomingMessage.<anonymous> (/Library/WebServer/Documents/discovery/tst.js:16:18)
at IncomingMessage.emit (events.js:67:17)
at HTTPParser.onBody (http.js:115:23)
at Socket.ondata (http.js:1150:24)
at TCP.onread (net.js:374:27)
Ответы
Ответ 1
Если вы действительно хотите поймать все исключения и предоставить некоторую обработку, отличную от выхода из процесса Node.js, вам нужно обработать Node uncaughtException событие.
Если вы думаете об этом, это Node вещь, а не вещь Express, потому что если вы выбросите исключение из какой-либо произвольной части кода, то нет гарантии, что Express может или когда-нибудь ее увидит, или будет положение, чтобы заманить его в ловушку. (Почему? Исключения не очень хорошо взаимодействуют с асинхронным кодом обратного вызова, управляемым событиями, который является стилем Node. Исключения перемещаются вверх по стеку вызовов, чтобы найти блок catch()
, который в области на момент генерирования исключения. myFunction
откладывает некоторую работу на функцию обратного вызова, которая запускается, когда происходит какое-либо событие, а затем возвращается к циклу событий, а затем, когда эта функция обратного вызова вызывается, она вызывается непосредственно из цикла основного события, а myFunction
больше не находится на стек вызовов, если эта функция обратного вызова генерирует исключение, даже если myFunction
имеет блок try/catch, он не поймает исключение.)
На практике это означает, что если вы выбросите исключение и не поймаете его самостоятельно, и вы сделаете это в функции, которая была непосредственно вызвана Express, Express может поймать исключение и вызвать обработчик ошибок, который вы установили, предполагая, что вы настроили часть промежуточного программного обеспечения обработки ошибок, например app.use(express.errorHandler())
. Но если вы выкинете одно и то же исключение в функцию, вызванную в ответ на асинхронное событие, Express не сможет ее поймать. (Единственный способ поймать его - прослушивать глобальное событие Node uncaughtException
, что было бы плохой идеей, прежде всего потому, что это глобально, и вам может понадобиться использовать его для других вещей, а во-вторых, потому что Express не будет идея, какой запрос был связан с исключением.)
Вот пример. Я добавляю этот фрагмент кода обработки маршрута в существующее приложение Express:
app.get('/fail/sync', function(req, res) {
throw new Error('whoops');
});
app.get('/fail/async', function(req, res) {
process.nextTick(function() {
throw new Error('whoops');
});
});
Теперь, если я посещаю http://localhost:3000/fail/sync
в своем браузере, браузер удаляет стек вызовов (показывая express.errorHandler в действии). Однако, если я посещаю http://localhost:3000/fail/async
в браузере, браузер злится (Chrome показывает "Нет данных: Ошибка 324, net:: ERR_EMPTY_RESPONSE: сервер закрыл соединение без отправки каких-либо данных" ), поскольку Node завершил процесс, показывая обратную трассировку на stdout в терминале, где я его вызывал.
Ответ 2
Чтобы улавливать асинхронные ошибки, я использую домен. С помощью Express вы можете попробовать этот код:
function domainWrapper() {
return function (req, res, next) {
var reqDomain = domain.create();
reqDomain.add(req);
reqDomain.add(res);
res.on('close', function () {
reqDomain.dispose();
});
reqDomain.on('error', function (err) {
next(err);
});
reqDomain.run(next)
}
}
app.use(domainWrapper());
//all your other app.use
app.use(express.errorHandler());
Этот код сделает вашу асинхронную ошибку захваченной и отправленной на ваш обработчик ошибок. В этом примере я использую express.errorHandler, но он работает с любым обработчиком.
Дополнительные сведения о домене: http://nodejs.org/api/domain.html
Ответ 3
Вы можете использовать обработчик ошибок по умолчанию, который выражает использование, которое на самом деле connect обработчик ошибок.
var app = require('express').createServer();
app.get('/', function(req, res){
throw new Error('Error thrown here!');
});
app.configure(function(){
app.use(express.errorHandler({ dumpExceptions: true, showStack: true }));
});
app.listen(3000);
Обновление
Для вашего кода вам действительно нужно зафиксировать ошибку и передать ее, чтобы выразить это как
var express = require('express');
var http = require('http');
var app = express.createServer();
app.get('/', function (req, res, next) {
console.log("debug", "calling");
var options = {
host:'www.google.com',
port:80,
path:"/"
};
http.get(options,
function (response) {
response.on("data", function (chunk) {
try {
console.log("data: " + chunk);
chunk.call(); // no such method; throws here
}
catch (err) {
return next(err);
}
});
}).on('error', function (e) {
console.log("error connecting" + e.message);
});
});
app.configure(function () {
app.use(express.errorHandler({ dumpExceptions:true, showStack:true }));
});
app.listen(3000);