web-dev-qa-db-ja.com

Expressでエラーを適切に処理する方法

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!');
});
_

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.jsdebuggerを使用して知ることができることから、next()が呼び出された後もコードブロックの実行は継続されます。つまり、req.send('event found!')が実行を試みます。これが起こらないようにしたい。

私が見つけた唯一の回避策は、「次へ」ではなく単にnew Error()をスローすることですが、これによりデフォルトのExpress HTMLエラーページが生成されます。それよりももう少しコントロールが欲しいのですが。

時間をかけてExpressのドキュメントの エラー処理セクション を読みましたが、理解できませんでした。

24
YWCA Hello

あなたはチェックアウトしたいと思うでしょう 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();
    });
});
_

不足しているスイートスポットはreturnnext(...)です

35
Chance

それはあなたがそれを間違っているからです:あなたはすでにエラーを投げました(それはExpressによって処理され、ユーザーのための500-エラーページまたはそのようなものを返します)がクライアントにあなた自身の応答を送信しようとしています: res.send( 'イベントが見つかりました!');

あなたは本当にここでエラー処理についてのエクスプレスガイドをチェックする必要があります: 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);
    }
});
19
alessioalex

コードにいくつかの問題があります。

  • クライアントに応答するときは、response objectresではなく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)
}); 
10
evilcelery