2015-10-29 43 views
32

私はExpressアプリケーション内で実行されているES6約束ベースのコードをたくさん持っています。捕捉されないエラーがある場合、私はそれに対処するために次のコードを使用しています。Expressアプリケーションで処理されなかった拒否

process.on('unhandledRejection', function(reason, p) { 
    console.log("Unhandled Rejection:", reason.stack); 
    process.exit(1); 
}); 

これはデバッグのためにうまくいきます。

しかし、私は500エラーハンドラをトリガして、ユーザに標準の「何かが間違っている」ページを表示したいと思います。

app.use(function(error, req, res, next) { 
    res.status(500); 
    res.render('500'); 
}); 

それは非同期だとError: Can't render headers after they are sent to the client.

でoffen結果は、私がレンダリングに行くかどうとして動作しませんミドルウェア内unhandledRejectionを置く:私はこのキャッチに現在他の例外のために働くすべてのエラーハンドラを持っていますunhandledRejectionの500ページ?

readFile() .then(readAnotherFile) .then(doSomethingElse) .then(...)

はあなたの約束鎖の末端に.catch(next)を追加し、エクスプレスのミドルウェアが正常に使用して、両方の同期/非同期コードを処理します:あなたはエクスプレスなどのようないくつかの約束ベースのコードを使用していると仮定すると

答えて

15

は...しばしばError: Can't render headers after they are sent to the client.

になり、わずかくださいExpressJS Documentationから

// production error handler 
const HTTP_SERVER_ERROR = 500; 
app.use(function(err, req, res, next) { 
    if (res.headersSent) { 
    return next(err); 
    } 

    return res.status(err.status || HTTP_SERVER_ERROR).render('500'); 
}); 

:あなたのエラーハンドラへの変更

Expressには、アプリケーションで発生する可能性のあるエラーを処理する内蔵のエラーハンドラが付属しています。このデフォルトのエラー処理ミドルウェアは、ミドルウェアスタックの最後に追加されます。

エラーをnext()に渡し、エラーハンドラで処理しないと、組み込みエラーハンドラによって処理されます。エラーはスタックトレースとともにクライアントに書き込まれます。スタックトレースは本番環境には含まれていません。

環境変数NODE_ENVを "production"に設定すると、本番モードでアプリが実行されます。

レスポンスの書き込みを開始した後でnext()を呼び出すと、たとえばクライアントにレスポンスをストリーミングしているときにエラーが発生した場合、Expressのデフォルトのエラーハンドラは接続を閉じ、要求は失敗したとみなされます。

カスタムエラーハンドラを追加すると、ヘッダーがすでにクライアントに送信されているときに、expressのデフォルトエラー処理メカニズムに委任したいと思うでしょう。

13

私はエラーハンドラを表現するために未処理の拒否を転送するcatchコールバック(別名エラーバック) としてnext引数を使用しています:

app.get('/foo', function (req, res, next) { 
    somePromise 
    .then(function (result) { 
     res.send(result); 
    }) 
    .catch(next); // <----- NOTICE! 
} 

または短い形式:

app.get('/foo', function (req, res, next) { 
    somePromise 
    .then(function (result) { 
     res.send(result); 
    }, next); // <----- NOTICE! 
} 

と高速エラーハンドラで意味のあるエラー応答 とerr引数を発行できます。例えば

app.use(function (err, req, res, /*unused*/ next) { 
    // bookshelf.js model not found error 
    if (err.name === 'CustomError' && err.message === 'EmptyResponse') { 
    return res.status(404).send('Not Found'); 
    } 
    // ... more error cases... 
    return res.status(500).send('Unknown Error'); 
}); 

IMHO、グローバルunhandledRejectionイベントは、究極の答えではありません。

app.use(function (req, res, next) { 
    process.on('unhandledRejection', function(reason, p) { 
    console.log("Unhandled Rejection:", reason.stack); 
    res.status(500).send('Unknown Error'); 
    //or next(reason); 
    }); 
}); 

が、これはTOO重いです:

例えば、これは、メモリリークを起こしやすいの約束のためのより良いサポートを必要とexpressjs

app.use(function (req, res, next) { 
    var l = process.once('unhandledRejection', function(reason, p) { 
    console.log("Unhandled Rejection:", reason.stack); 
    res.status(500).send('Unknown Error'); 
    //next(reason); 
    }); 
    next(); 
    process.removeEventLister('unhandledRejection', l); 
}); 

IMHO、。

+0

私たちは常にエラーを処理するために 'next'を使い、約束の拒否のためのグローバルエラーハンドラはありません(これはとても悪いです! –

2

私はexpress-promise-routerがこの問題を正確に解決するために作られたと思います。それはあなたのルートが約束を返すことを可能にし、そのような約束がエラーで拒否された場合はnext(err)と呼ぶでしょう。

関連する問題