【问题标题】:ExpressJS error handling doesn't workExpressJS 错误处理不起作用
【发布时间】:2017-04-07 22:38:59
【问题描述】:

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

顺便说一句,错误确实被写入控制台(但不是我的函数),并且应用程序不会崩溃。

我要做的是一个通用的解决方案,它将在一个地方捕获每个未处理的异常。

我做错了什么?

【问题讨论】:

  • 你是如何定义你的请求的? app.get(req, res)???
  • @LucasKatayama 是的
  • Express 已经有一个默认的错误处理程序,它可能是记录错误的那个。我的猜测是你正在安装你的错误处理程序,它不是最后一个中间件,但我不能肯定地说不知道你的应用程序的结构(是server.js应用程序入口点,还是你通过其他文件启动应用程序?)
  • @robertklep 我这样启动我的应用程序:“node server.js”,这是第一个被执行的文件。
  • @Alon 嗯,听起来不错。我相当肯定,由于某种原因,您的错误处理程序没有正确注册,并且默认错误处理程序启动。您可以尝试在调试模式下运行您的应用程序,看看这是否能说明正在发生的事情:@987654325 @

标签: javascript node.js express error-handling


【解决方案1】:

我认为问题出在路由定义上

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

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

试试这个:

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

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

为什么?

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

【讨论】:

  • 我已经简化了我的代码。我实际上从我调用的函数中得到了一个错误。我可以用 try/catch 块捕获它,但我不想在每个 app.get 函数中添加一个 try/catch 块。我想要一个通用的解决方案,可以在一个地方捕获所有未处理的异常。
  • 正如您在我的代码中看到的,我研究了这个主题。我只是无法找到我做错了什么。您发送的示例在我看来就像我的代码。我一定错过了什么。
  • 路由内的 throw 会通过 express 自动调用 next(err)。
【解决方案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 错误处理程序的输出。

【讨论】:

  • 另一个建议是你之前有另一个错误处理程序,它打印出错误消息但没有使用next(err)进一步传递控制
【解决方案3】:

如果你想让全局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)

如果你得到错误的顺序,当有东西被抛出时,就不会调用错误处理程序。

【讨论】:

    【解决方案4】:

    注意:您的错误处理程序中间件必须有 4 个参数:error、req、res、next。否则你的处理程序不会触发。

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

    【讨论】:

      猜你喜欢
      • 2020-07-02
      • 2018-10-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-02-01
      • 1970-01-01
      • 2011-03-03
      • 1970-01-01
      相关资源
      最近更新 更多