ExpressJS错误处理不起作用

时间:2016-11-23 19:24:13

标签: javascript node.js express error-handling

在我的server.js文件的最后,我有以下代码:

app.use(logErrors);

function logErrors (err: Error, req: Request, res: Response, next: NextFunction) {
    console.log(err);
    mongoDal.log(err.message, err);
    next(err);
}

但发生错误时无法访问此代码。

我也有Node.js错误处理功能,但是没有达到:

process.on('uncaughtException', function (err: Error) {
    try {
        console.log(err);
        mongoDal.log(err.message, err);
    } catch (err) {

    }
});

这是产生错误的代码:

app.get('/test_feature', function (req: Request, res: Response) {
    makeError();

    res.send("Done");
});

function makeError(){
    throw new Error("asdasdad");
}

BTW错误确实被写入控制台(但不是我的函数),应用程序不会崩溃。

我尝试制作的是一种通用解决方案,可以在一个地方捕获每个未处理的异常。

我做错了什么?

4 个答案:

答案 0 :(得分:2)

以下是处理3种错误的简短工作示例: 1)传递给next()处理程序, 2)抛出内部路由处理程序, 3)从路由处理程序调用的某个函数的回调内部未处理的错误。

(1)和(2)使用自定义错误中间件处理程序(A)捕获,(3)由uncaughtException处理程序(B)捕获。

Express有自己的错误处理程序,如果它使用next()调用链获得控件(即如果没有自定义错误处理程序或者如果它使用next(err, req, res, next)进一步传递控件),则会输出错误。这就是为什么你仍然在控制台中收到错误信息,即使你的处理程序不是触发器。

如果您尝试运行案例(1)和(2)的示例,您将看到错误输出两次 - 通过自定义处理程序(A)和默认的Express错误处理程序。

'use strict';

var express = require('express');
var app = express();    

var server = app.listen(8080, function() {
  console.log('* Server listening at ' + server.address().address + ':' + server.address().port);
});

// Example 1: Pass error in route handler to next() handler
app.use('/1', function(req, res, next) {
  console.log('* route 1');
  next(new Error('* route 1 error'));
});

// Example 2: throw the error in route handler
app.use('/2', function(req, res, next) {
  console.log('* route 2');
  throw new Error('route 2 error');
});

// Example 3: unhandled error inside some callback function
app.use('/3', function(req, res, next) {
  console.log('* route 3');
  setTimeout(function(){
    throw new Error('route 3 error');
  }, 500);
});

// Error handler A: Express Error middleware
app.use(function(err, req, res, next) {
  console.log('**************************');
  console.log('* [Error middleware]: err:', err);
  console.log('**************************');
  next(err);
});

// Error handler B: Node's uncaughtException handler
process.on('uncaughtException', function (err) {
  console.log('**************************');
  console.log('* [process.on(uncaughtException)]: err:', err);
  console.log('**************************');
});

节点版本:v7.2.0

典型错误是在路由定义之前放置错误处理程序,但根据您的描述并非如此。

要找到问题,您可以尝试将自己的代码缩小到与我相同的大小,我认为问题会变得很明显。

更新

此外,如果我尝试运行您提供的代码(通过简单的修改),它对我有用:

'use strict';

var express = require('express');
var app = express();

var server = app.listen(8080, function() {
  console.log('* Server listening at ' + server.address().address + ':' + server.address().port);
});

//process.on('uncaughtException', function (err: Error) {
process.on('uncaughtException', function (err) {
  try {
    console.log('*** uncaughtException:', err);
    //mongoDal.log(err.message, err);
  } catch (err) {

  }
});

//app.get('/test_feature', function (req: Request, res: Response) {
app.get('/test_feature', function (req, res) {
  makeError();
  res.send("Done");
});

function makeError(){
  throw new Error("asdasdad");
}

app.use(logErrors);

//function logErrors (err: Error, req: Request, res: Response, next: NextFunction) {
function logErrors (err, req, res, next) {
  console.log('*** logErrors:', err);
  //mongoDal.log(err.message, err);
  next(err);
}

结果是(堆栈跟踪被截断):

* Server listening at :::8080
*** logErrors: Error: asdasdad
    at makeError (/home/alykoshin/sync/al-projects/dev/nmotw/400-express-error-handling/main-stackoverflow.js:32:9)
...........
Error: asdasdad
    at makeError (/home/alykoshin/sync/al-projects/dev/nmotw/400-express-error-handling/main-stackoverflow.js:32:9)
...........

您可能会在开头看到logErrors处理程序的输出,然后是默认Express错误处理程序的输出。

答案 1 :(得分:1)

注意:您的错误处理程序中间件必须具有4个参数:error,req,res,next。否则,您的处理程序将不会解雇。

我一直在解决这个问题,直到我发现了这个问题。

答案 2 :(得分:0)

我认为问题在于路由定义

正如你所说,你正在使用这个

with mv   -- The derived table finds the quote with the highest volume.
as
(
    select customerID
            ,quoteNo
            ,max(volume) as maxVolume
    from customerQuote
    group by customerID
            ,quoteNo
)
select c.customerID      -- Which you then use to find the lowest price at that volume.
        ,c.quoteNo
        ,mv.maxVolume
        ,min(c.price) as minPrice
from customerQuote c
    inner join mv
        on c.customerID = mv.customerID
            and c.quoteNo = mv.quoteNo
            and c.volume = mv.maxVolume
group by c.customerID
        ,c.quoteNo
        ,mv.maxVolume;

尝试使用:

app.get('/test_feature', function (req, res) {
    throw new Error("asdasdad");
    res.send("Done");
});

然后将res.send放在错误处理程序...

<强>为什么吗

我认为在函数内部抛出一个Error会停止请求链...所以它不会到达最终结果,然后是错误处理程序。 如果你以第二种方式写作......你向前移动错误......然后到达你的处理程序......

答案 3 :(得分:0)

如果您想要运行全局uncaughtException,则需要在没有人捕获的地方抛出错误,如下所示:

app.get('/test_feature', function (req: Request, res: Response) {
    setTimeout(function () { throw new Error('oops'); }, 1000);

    res.send("Done");
});

处理程序内部的同步throw由express捕获, 捕获时,根本不会发生uncaughtException

根据http://expressjs.com/en/guide/error-handling.html,在您的路由和其他中间件后,定义了一个错误处理中间件。

app.get('/test_feature', function (req: Request, res: Response) {
    makeError();

    res.send("Done");
});

app.use(logErrors)

如果输入错误,则在抛出某些内容时不会调用错误处理程序。