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;
我这里有一个基本的快递http服务器。这个服务器有一个路由dosomething,它可以进行两次网络呼叫并告诉用户它们是否成功。
这是我的整个网络服务器(出于示例目的,这是我实际服务器的一个简单的服务器)。我现在担心这个服务器崩溃了。阅读文档以表达我看到有一个默认的错误处理程序,它将捕获错误并防止服务器崩溃(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中,它将捕获并处理所有错误,但这似乎不是这样的情况?在我的异步函数内部,例如你可以看到我正在查看是否返回了错误,如果是我向用户发送错误,但如果发生其他错误怎么办,怎样才能获得快速捕获并处理此错误对我来说?
答案 0 :(得分:0)
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);
});
服务器会崩溃,因为回调实际上是在另一个上下文中,它抛出的异常现在将由原始捕获器捕获。在回调时,这是一个非常难以处理的问题。
虽然有多个解决方案。一个可能的解决方案是使用try
catch
语句包装每个容易抛出错误的函数。但这有点过分了。
例如:
app.get('/a', function(req, res) {
setTimeout(function () {
try {
var x = JSON.parse('{');
}
catch (err) {
res.send(err.message);
}
}, 1000);
});
一个更好的解决方案,就是使用promises,如果可能的话,那么例如你可以像这样声明一个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);
}
这是一个非常简化的示例,但您可以为其添加更多功能,并且(至少在理论上)具有单一捕获语句,这将阻止您的服务器崩溃。