如何让express处理和捕获我的错误


var database = require('database');
var express = require('express');
var app = express();
var cors = require('cors');
app.use(cors());
var bodyParser = require('body-parser');
var urlencodedParser = bodyParser.urlencoded({
extended: false
});

app.post('/dosomething', urlencodedParser, function(req, res) {
if (!req.body.a) {
res.status(500).send(JSON.stringify({
error: 'a not defined'
}));
return;
}

firstAsyncFunction(req.body.a, function(err, result) {
if (err) {
res.status(500).send('firstAsyncFunction was NOT a success!');
} else {
if (result.b) {
secondAsyncFunction(result.b, function(err, data) {
if (err) {
res.status(500).send('secondAsyncFunction was NOT a success!');
return;
}
res.send('EVERYTHING WAS A SUCCESS! ' + data);
});
}
else {
res.status(500).send('result.b is not defined');
}
}
}); 
});
function firstAsyncFunction(param, callback) {
//Some network call:
// Return either return (callback(null,'success'));  or return (callback('error'));
var query = database.createQuery(someOptionsHere);
database.runDatabaseQuery(query, function(err, entities, info) {
if (err) {
return (callback('error'));
}
return (callback(null, 'success'));
});
};
function secondAsyncFunction(param, callback) {

//Some network call:
// Return either return (callback(null,'success'));  or return (callback('error'));
var query = database.createQuery(someOptionsHere);
database.runDatabaseQuery(query, function(err, entities, info) {
if (err) {
return (callback('error'));
}
return (callback(null, 'success'));
});
};

var server = app.listen(process.env.PORT || 3000, function() {
var host = server.address().address;
var port = server.address().port;
console.log('App listening at http://%s:%s', host, port);
});

module.exports = app;

我这里有一个基本的express http服务器。该服务器有一个路由dosomething,它进行两次网络呼叫,并告诉用户它们是否成功。

这是我的整个Web服务器(例如,这是我实际服务器的一个基本服务器)。我现在担心这个服务器崩溃。阅读express的文档,我发现有一个默认的错误处理程序,它可以捕获错误并防止服务器崩溃(http://expressjs.com/en/guide/error-handling.html)。我添加了代码:

function defaultErrorHandler(err, req, res, next) {
if (res.headersSent) {
return next(err);
}
res.status(500);
res.render('error', { error: err });
}
app.use(defaultErrorHandler);

不过,这仍然会使我的服务器崩溃。例如我的数据库返回了一个不正确的JSON响应,我遇到了问题,在我的firstAsyncFunction(代码中未显示)中,我试图解析JSON,但它导致了一个错误,告诉我这是不正确的JSON,服务器崩溃了,在我重新启动它之前无法再接受请求。我希望避免这种情况,并让默认的错误处理程序在发生这种情况时向用户发送一个通用响应。我想如果我指定defaultErrorHandler并将其放在app.use中,它会捕获并处理所有错误,但事实似乎并非如此?例如,在我的异步函数内部,你可以看到我正在查看是否返回了错误,如果是,我会向用户发送一个错误,但如果发生了其他错误,我该如何让express为我捕获和处理这个错误?

defaultErrorHandler无法处理异步任务内部抛出的异常,例如回调。

如果你定义了一条路线,比如:

app.get('/a', function(req, res) {
throw new Error('Test');
});

将抛出一个错误,在这种情况下,defaultErrorHandler将成功捕获它

如果相同的异常以异步方式发生,如下图所示:

app.get('/a', function(req, res) {
setTimeout(function () {
throw new Error('Test');
}, 1000);
});

服务器将崩溃,因为回调实际上在另一个上下文中,它引发的异常现在将被原始捕获器捕获。当涉及到回调时,这是一个很难处理的问题。

不过,解决方案不止一种。一个可能的解决方案是用trycatch语句包装每个容易抛出错误的函数。不过这有点过分。

例如:

app.get('/a', function(req, res) {
setTimeout(function () {
try {
var x = JSON.parse('{');
}
catch (err) {
res.send(err.message);
}
}, 1000);
});

一个更好的解决方案:

一个更好的解决方案是使用promise,如果可能的话,那么例如,您可以声明一个errorHandler函数,如下所示:

function errorHandler(error, res) {
res.send(error.message);
}

然后,假设您必须使用以下函数从数据库中获取内容(我使用setTimeout来模拟异步行为):

function getStuffFromDb() {
return new Promise(function (resolve, reject) {
setTimeout(function () {
resolve("{");
}, 100);
});
}

请注意,此函数返回一个无效的JSON字符串。你的路线看起来像:

app.get('/a', function(req, res) {
getStuffFromDb()
.then(handleStuffFromDb)
.catch(function (error) { errorHandler(error, res) });
});
function handleStuffFromDb(str) {
return JSON.parse(str);
}

这是一个非常简单的例子,但您可以为它添加更多的功能,并且(至少在理论上)有一个single-catch语句,这将防止您的服务器崩溃。

最新更新