【问题标题】:How to have express handle and capture my errors如何快速处理并捕获我的错误
【发布时间】:2016-06-09 05:20:26
【问题描述】:
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 服务器。这个服务器有一个路由,dsomething,它会进行两次网络调用并告诉用户它们是否成功。

这是我的整个网络服务器(出于示例目的,这是我的实际服务器的基本服务器)。我现在担心这台服务器崩溃。阅读 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 中,它会捕获并处理所有错误,但似乎不是这样?例如,在我的异步函数内部,您可以看到我正在查看是否返回了错误,如果是,我将错误发送回用户,但是如果发生其他错误怎么办,我怎样才能快速捕获和处理此错误给我?

【问题讨论】:

  • 试试这个connect-domain
  • 我刚刚读到 nodejs 中不推荐使用域 API

标签: javascript node.js express error-handling


【解决方案1】:

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

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

【讨论】:

    猜你喜欢
    • 2021-04-22
    • 1970-01-01
    • 2013-11-24
    • 2018-10-07
    • 1970-01-01
    • 2015-06-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多