如何正确处理 Express 中的错误?

Posted

技术标签:

【中文标题】如何正确处理 Express 中的错误?【英文标题】:How to properly handle errors in Express? 【发布时间】:2011-12-04 17:25:32 【问题描述】:

我开始使用 Express JS 并遇到了问题。我似乎无法找出处理错误的正确方法。

例如,我有一个 Web 服务 API,它为一个名为“事件”的对象提供服务。当用户提交未找到的事件 ID 时,我想返回一个简单的“找不到事件”字符串。以下是我目前构建代码的方式:

app.get('/event/:id', function(req, res, next) 
    if (req.params.id != 1) 
        next(new Error('cannot find event ' + req.params.id));
    

    req.send('event found!');
);

当我提交 id 不是 1 时,Node 崩溃并显示以下输出:

http.js:527
   throw new Error("Can't set headers after they are sent.");
         ^
Error: Can't set headers after they are sent.
    at ServerResponse.<anonymous> (http.js:527:11)
    at ServerResponse.setHeader (/usr/local/kayak/node_modules/express/node_modules/connect/lib/patch.js:62:20)
    at /usr/local/kayak/node_modules/express/node_modules/connect/lib/middleware/errorHandler.js:72:19
    at [object Object].<anonymous> (fs.js:107:5)
    at [object Object].emit (events.js:61:17)
    at afterRead (fs.js:878:12)
    at wrapper (fs.js:245:17)

据我所知,使用 node.js 调试器,在调用 next() 之后继续执行代码块,这意味着 req.send('event found!') 尝试运行。我不希望这种情况发生。

我发现的唯一解决方法是简单地抛出 new Error() 而不是“下一步”它,但这会导致生成默认的 Express html 错误页面。我想要更多的控制权。

我花时间阅读了 Express 文档中的 error handling section,但我无法理解它。

【问题讨论】:

【参考方案1】:

您需要查看Express Error Handling。从那里:

app.param('userId', function(req, res, next, id) 
    User.get(id, function(err, user) 
        if (err) return next(err);
        if (!user) return next(new Error('failed to find user'));
        req.user = user;
        next();
    );
);

您缺少的最佳位置是 return next(...)

【讨论】:

【参考方案2】:

那是因为你做错了:你已经抛出了一个错误(这将由 Express 处理并返回一个 500 - 用户的错误页面或类似的东西),但你也试图将自己的响应发送到客户端:res.send('找到事件!');

您真的应该在此处查看有关错误处理的 Express 指南:http://expressjs.com/guide/error-handling.html

在你的例子中我会做的是:

function NotFound(msg)
  this.name = 'NotFound';
  Error.call(this, msg);
  Error.captureStackTrace(this, arguments.callee);
 

app.get('/event/:id', function(req, res, next)
  if (req.params.id != 1) 
    throw new NotFound('Cannot find event ' + req.params.id);
   else 
    res.send('event found!');
  
);

app.error(function(err, req, res, next)
    if (err instanceof NotFound) 
        res.render('404.ejs');
     else 
        next(err);
    
);

【讨论】:

链接中的快速文档很差。它甚至没有提到你应该如何正确地抛出一个错误,或者哪个版本的表达它有效。 这是 Express 3.x 的链接,如果您想了解更多关于 2.x 中的错误处理的信息,请查看此链接:expressjs.com/2x/guide.html#error-handling 哦,具有讽刺意味的是:答案中的错误处理程序链接返回 GitHub 404。这是当前活动链接:expressjs.com/guide/error-handling.html 应该是 res.send,而不是 req.send【参考方案3】:

您的代码中有几个问题:

在响应客户端时,需要使用response对象res而不是req)。

李>

next 发送错误时,您应该返回,这样函数的其余部分就不会运行。

李>

这是修复这些错误后的代码:

app.get('/event/:id', function(req, res, next) 
    if (req.params.id != 1) 
        return next(new Error('cannot find event ' + req.params.id));
    

    res.send('event found!'); // use res.send (NOT req.send)
); 

【讨论】:

以上是关于如何正确处理 Express 中的错误?的主要内容,如果未能解决你的问题,请参考以下文章

节点 express REST API 中的 CORS 错误(PATCH 请求)

使用带有 expressjs 的 multer 上传文件时的错误处理

Express Passport (node.js) 错误处理

在 typescript node+express 项目中使用模块中的 typescript 文件的正确方法?当前抛出错误:找不到模块

express中的错误处理

koa 学习笔记