28

私は Express のドキュメントを調べましたが、エラー処理を説明する部分は完全にわかりません。

app彼らが言及しているのはインスタンスだと思いましたよねcreateServer()?しかし、リクエストの処理中に例外が発生したときに、node.js がアプリケーション プロセスを爆破するのを止める方法がわかりません。

派手なものは本当に必要ありません。例外が発生するたびに、ステータス 500 と空の応答を返したいだけです。キャッチされない例外がどこかにあったという理由だけで、ノード プロセスを終了してはなりません。

これを達成する方法の簡単な例はありますか?


var express = require('express');
var http = require('http');

var app = express.createServer();

app.get('/', function(req, res){
    console.log("debug", "calling")
    var options = {
        host: 'www.google.com',
        port: 80,
        path: "/"
    };
    http.get(options, function(response) {
       response.on("data", function(chunk) {
           console.log("data: " + chunk);
           chunk.call(); // no such method; throws here
       });
    }).on('error', function(e) {
       console.log("error connecting" + e.message);
    });
});

app.configure(function(){
    app.use(express.errorHandler({ dumpExceptions: true, showStack: true }));
});

app.listen(3000);

アプリ全体がクラッシュし、トレースバックが生成されます

mypath/tst.js:16
           chunk.call(); // no such method; throws here
                 ^ TypeError: Object ... has no method 'call'
    at IncomingMessage.<anonymous> (/Library/WebServer/Documents/discovery/tst.js:16:18)
    at IncomingMessage.emit (events.js:67:17)
    at HTTPParser.onBody (http.js:115:23)
    at Socket.ondata (http.js:1150:24)
    at TCP.onread (net.js:374:27)
4

4 に答える 4

47

本当にすべての例外をキャッチして、Node.js プロセスを終了する以外の処理を提供したい場合は、Node のuncaughtExceptionイベントを処理する必要があります。

考えてみれば、これはノードの問題であり、Express の問題ではありません。任意のコードから例外をスローした場合、Express がそれを認識できる、または認識できる、またはトラップできるという保証はないからです。 . (なぜですか? 例外は、Node スタイルである非同期イベント駆動型のコールバック コードとうまくやり取りしません。例外は、コール スタックを上ってcatch()、例外がスローされた時点でスコープ内にあるブロックを見つけmyFunctionます。何らかのイベントが発生したときに実行され、イベント ループに戻るコールバック関数が呼び出されると、メインのイベント ループから直接呼び出さmyFunctionれ、コール スタックから削除されます。このコールバック関数が例外をスローすると、もしそれでもmyFunctiontry/catch ブロックがあり、例外をキャッチしません。)

これが実際に意味することは、例外をスローして自分でキャッチせず、Express によって直接呼び出された関数で例外をスローした場合、Express は例外をキャッチし、インストールしたエラー ハンドラーを呼び出すことができるということです。のようなエラー処理ミドルウェアを構成しapp.use(express.errorHandler())ました。ただし、非同期イベントに応答して呼び出された関数で同じ例外をスローすると、Express はそれをキャッチできません。(それをキャッチできる唯一の方法は、グローバルな NodeuncaughtExceptionイベントをリッスンすることです。これは、最初はグローバルであり、他の目的で使用する必要がある可能性があるため、悪い考えです。次に、Express はどの要求が関連付けられているかがわからないためです。例外あり。)

これが例です。このルート処理コードのスニペットを既存の Express アプリに追加します。

app.get('/fail/sync', function(req, res) {
   throw new Error('whoops');
});
app.get('/fail/async', function(req, res) {
   process.nextTick(function() {
      throw new Error('whoops');
   });
});

ブラウザでアクセスhttp://localhost:3000/fail/syncすると、ブラウザはコール スタックをダンプします (express.errorHandler が動作していることを示しています)。http://localhost:3000/fail/asyncただし、ブラウザでアクセスすると、ノードプロセスが終了したため、ブラウザが怒ります (Chrome は「データを受信しませんでした: エラー 324、net::ERR_EMPTY_RESPONSE: サーバーはデータを送信せずに接続を閉じました」というメッセージを表示します)。呼び出した端末の stdout にバックトレースを表示します。

于 2013-04-09T21:48:44.137 に答える
10

非同期エラーをキャッチできるようにするために、ドメインを使用します。Express を使用すると、次のコードを試すことができます。

function domainWrapper() {
    return function (req, res, next) {
        var reqDomain = domain.create();
        reqDomain.add(req);
        reqDomain.add(res);

        res.on('close', function () {
            reqDomain.dispose();
        });
        reqDomain.on('error', function (err) {
            next(err);            
        });
        reqDomain.run(next)
    }
}
app.use(domainWrapper());
//all your other app.use
app.use(express.errorHandler());

このコードにより、非同期エラーがキャプチャされ、エラー ハンドラーに送信されます。この例では、express.errorHandler を使用していますが、どのハンドラーでも機能します。

ドメインの詳細については、http: //nodejs.org/api/domain.htmlを参照してください。

于 2014-03-02T11:49:23.530 に答える
2

明示的に使用するデフォルトのエラー ハンドラを使用できます。これは、実際にはconnect error handlerです。

var app = require('express').createServer();

app.get('/', function(req, res){
  throw new Error('Error thrown here!');
});

app.configure(function(){
    app.use(express.errorHandler({ dumpExceptions: true, showStack: true }));
});

app.listen(3000);

更新 コードの場合、実際にはエラーをキャプチャして、このように表現するために渡す必要があります

var express = require('express');
var http = require('http');

var app = express.createServer();

app.get('/', function (req, res, next) {
  console.log("debug", "calling");
  var options = {
    host:'www.google.com',
    port:80,
    path:"/"
  };
  http.get(options,
    function (response) {
      response.on("data", function (chunk) {
        try {
          console.log("data: " + chunk);
          chunk.call(); // no such method; throws here

        }
        catch (err) {
          return next(err);
        }
      });
    }).on('error', function (e) {
      console.log("error connecting" + e.message);
    });
});

app.configure(function () {
  app.use(express.errorHandler({ dumpExceptions:true, showStack:true }));
});

app.listen(3000);
于 2012-04-30T22:44:55.120 に答える
1

express 5.0.0-alpha.7 は 27 日前に出ました。この非常に具体的なプレリリース バージョンでは、最終的にリクエスト ハンドラー内の promise を拒否できるようになり、適切に処理されます。

ミドルウェアとハ​​ンドラーは Promise を返すことができるようになり、Promise が拒否された場合、拒否の値が err である next(err) が呼び出されます。(ソース)

例えば:

app.get('/', async () => {
    throw new Error();
});
app.use((err, req, res, next) => {
    res.status(500).send('unexpected error :(');
});

ただし、これはフォールバックとしてのみ使用してください。適切なエラー処理は、適切なエラー ステータス コードを使用して、リクエスト ハンドラー自体のキャッチフレーズ内で行われる必要があります。

于 2018-11-22T23:38:27.583 に答える