如何快速处理并捕获我的错误

时间:2016-06-09 05:20:27

标签: javascript node.js express error-handling

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中,它将捕获并处理所有错误,但这似乎不是这样的情况?在我的异步函数内部,例如你可以看到我正在查看是否返回了错误,如果是我向用户发送错误,但如果发生其他错误怎么办,怎样才能获得快速捕获并处理此错误对我来说?

1 个答案:

答案 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);
}

这是一个非常简化的示例,但您可以为其添加更多功能,并且(至少在理论上)具有单一捕获语句,这将阻止您的服务器崩溃。