Node.js + Express.jsアプリケーションのエラー処理原則?


177

エラー報告/処理がNode.js +で異なる方法で行われているようです他のフレームワークと比較して Express.jsアプリケーションです。私はそれが次のように機能することを理解して正しいですか?

A) 検出エラーをコールバック関数へのパラメーターとして受け取ることでエラーをします。例えば:

doSomethingAndRunCallback(function(err) { 
    if(err) {  }
});

B) レポート next(err)を呼び出して、MIDDLEWAREのエラーをます。例:

handleRequest(req, res, next) {
    // An error occurs…
    next(err);
}

C) レポートエラーをスローすることにより、ROUTESのエラーをします。例:

app.get('/home', function(req, res) {
    // An error occurs
    throw err;
});

D) ハンドル app.errorを経由して、独自のエラーハンドラを設定することによって、エラー()または一般的な接続エラーハンドラを使用します。例:

app.error(function(err, req, res, next) {
    console.error(err);
    res.send('Fail Whale, yo.');
});

これらの4つの原則は、Node.js + Express.jsアプリケーションでのすべてのエラー処理/レポートの基礎ですか?

回答:


183

Node.jsでのエラー処理は通常、A)の形式です。ほとんどのコールバックは、最初の引数としてエラーオブジェクトを返しますnull

Express.jsはミドルウェアを使用し、ミドルウェア構文はB)およびE)を使用します(下記参照)。

C)あなたが私に尋ねるなら、悪い習慣です。

app.get('/home', function(req, res) {
    // An error occurs
    throw err;
});

上記のように簡単に書き換えることができます

app.get('/home', function(req, res, next) {
    // An error occurs
    next(err);
});

ミドルウェア構文はgetリクエストで有効です。

D)について

(07:26:37 PM)tjholowaychuk:3.xでapp.errorが削除されました

TJはちょうどそれを確認しました app.errorは、Eを支持して非推奨であることを

E)

app.use(function(err, req, res, next) {
  // Only handle `next(err)` calls
});

長さが4(4つの引数)のミドルウェアは、エラーミドルウェアと見なされます。1つの呼び出しがnext(err)接続すると、エラーベースのミドルウェアが呼び出されます。


11
ありがとう!将来これに遭遇する可能性のある人にとっては、「メソッドe」のパラメータの順序は実際にはerr、req、res、nextのようです(req、res、next、errではなく)。
クリントハリス

9
これは見栄えがいいですが、私が目にしている問題は、一部のエラーが、説明したエラーハンドラーに届かず、process.on( 'uncaughtException'、fn)ハンドラーでしかキャッチできないことです。従来の知恵は、それを実現させ、アプリを再起動するためにForeverなどに依存することでしたが、その場合、どのようにしてフレンドリーなエラーページを返しますか?
ポール、

1
@chovyまた、単なるfyi。エラーハンドラは、スローされた/次のエラーのにアプリ渡す必要があります。以前の場合、エラーをキャッチしません。
Lee Olayvar

3
next(err)は基本的にエラーをスローするExpressのバージョンですが、独自のミドルウェア内で明示的に呼び出す必要があります
qodeninja

1
@qodeninjaその方法はExpressのベストプラクティスと見なされています。
David Oliveros 2014

11

Joyentの人々は、これについて本当に洞察に満ちたベストプラクティスドキュメントを公開しています。Node.js開発者向けの必読記事。



すばらしい記事、Joyentの更新されたドキュメントを指すようにリンクを修正しました。
stephbu

2
記事は悪くない:しかし、テキストが多すぎて例が十分ではない
-Gerd

3

なぜ最初のパラメータですか?

Node.jsは非同期の性質を持つため、first-parameter-as-errパターンはユーザーランドのNode.jsエラー処理の規約として確立されています。これは非同期だからです:

try {
    setTimeout(function() {
        throw 'something broke' //Some random error
    }, 5)
}
catch(e) {
   //Will never get caught
}

したがって、コールバックの最初の引数を持つことは、エラーをスローする以外に、非同期でエラーを渡す唯一の賢明な方法です。

そうすることは unhandled exceptionそれが聞こえるように、アプリケーションを混乱状態から抜け出すために何も行われなかったことを意味します。

例外、なぜ存在するのか

ただし、Node.jsの実質的にすべての部分がイベントエミッタであり、例外のスローがすべてのイベントと同様に処理できる低レベルのイベントであることは注目に値します。

//This won't immediately crash if connection fails
var socket = require("net").createConnection(5000);
socket.on("error", function(err) {
    console.error("calm down...", err)
});

これすべてのエラーキャッチするために極端にすることはできませんが、すべきではありませんクラッシュしないように一生懸命試みるアプリケーションを作成するためにすることはできませんが、すべきではありません。これは、ほとんどすべてのユースケースでひどい考えです。これは、アプリケーションの状態で何が起こっているのかまったくわからないままになり、mainをtry-catchでラップすることに似ているためです。

ドメイン-イベントを論理的にグループ化

アプリケーションがフォールオーバーする例外のこの問題への対処の一環として、ドメインを使用すると、開発者は、たとえばExpress.jsアプリケーションを取得して、致命的な障害が発生した場合に接続を意図的に切断することができます。

ES6

ES6ではジェネレーターパターンで非同期イベントを作成できるため、これが再度変更され、try / catchブロックで引き続きキャッチできることについて言及している可能性があります。

Koa(Express.jsの同じ原作者であるTJ Holowaychuckによって書かれた)はこれを顕著に行います。ES6 yieldステートメントを使用して、ほとんど同期しているように見えながら、通常のノード非同期方式で処理されるブロックを作成します。

app.use(function *(next) {
    try {
        yield next;
    } 
    catch (err) {
        this.status = err.status || 500;
        this.body = err.message;
        this.app.emit('error', err, this);
    }
});

app.use(function *(next) {
    throw new Error('some error');
})

この例はここから恥知らずに盗まれました

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.