如何在Express中正确地处理错误?

24
我开始使用Express JS并遇到了一个问题。 我似乎无法找到处理错误的正确方法。
例如,我有一个名为“event”的对象的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!');
});

当我提交除1以外的id时,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()而不是通过 next()。但这将导致生成默认的 Express HTML 错误页面,我需要更多控制权。
我花时间阅读了 Express 文档中的错误处理部分,但是无法理解。
3个回答

35

你需要查看Express错误处理。从那里开始:

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(...)

18

这是因为您做错了:您已经抛出了一个错误(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);
    }
});

5
这个链接提供的文档还比较简陋。它甚至没有提到如何正确地抛出错误,或者适用于哪个版本的 Express。 - UpTheCreek
这是 Express 3.x 的链接,如果你想了解更多关于 2.x 中的错误处理,请查看此链接:http://expressjs.com/2x/guide.html#error-handling - alessioalex
哦,讽刺的是:答案中的错误处理程序链接返回了 GitHub 404。这是当前有效的链接:http://expressjs.com/guide/error-handling.html - spamguy
应该使用 res.send,而不是 req.send。 - SubliemeSiem

10

您的代码存在几个问题:

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

  • 当将错误发送给next时,您应该return,以便函数的余下部分不再运行。

这是修复了上述错误后的代码:

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接