2012-04-30 3 views
22

Ich ging durch die Dokumentation von Express, und the part describing error handling ist völlig undurchsichtig für mich.Wie behandelt man Code-Ausnahmen in node.js?

Ich dachte, die app sie beziehen sich auf eine Instanz ist createServer(), richtig? Aber ich habe keine Ahnung, wie Sie verhindern können, dass node.js den Anwendungsprozess sprengt, wenn während der Bearbeitung einer Anfrage eine Ausnahme auftritt.

Ich brauche wirklich nichts Besonderes; Ich möchte nur einen Status von 500 und eine ansonsten leere Antwort zurückgeben, wenn es eine Ausnahme gibt. Der Knotenprozess darf nicht beenden, nur weil irgendwo eine nicht abgefangene Ausnahme aufgetreten ist.

Gibt es ein einfaches Beispiel, wie dies zu erreichen ist?


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

stürzt die gesamte App, Zurückverfolgungs

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) 
+0

', nur weil es eine abgefangene Ausnahme somewhere.' Der Prozess war *** wird *** sterben, wenn es eine * abgefangene * Ausnahme. Wenn Sie nicht möchten, dass es beim Auftreten einer Ausnahme beendet wird, fangen Sie die Ausnahme ab und geben 500 Fehler zurück. – Chad

+2

Sie könnten sich für die nicht-Express-Art interessieren: http://StackOverflow.com/Questions/4213351/Make-Node-JS-Not-Exit-On-Fehler – Matt

+0

Ausgezeichnet, vielen Dank @Matt! – user124114

Antwort

2

produzieren Sie können den Standardfehlerhandler verwenden, die Anwendungen ausdrücken, die eigentlich connect error handler ist.

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

aktualisieren für Ihren Code, müssen Sie tatsächlich den Fehler erfassen und weitergeben wie diese

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); 
+0

Ihr Beispiel funktioniert (nach dem Hinzufügen von 'var express = require ('express');'), aber leider, wenn ich das gleiche in meinem Code tun, stürzt es immer noch den Prozess ab. Ich habe die Frage mit Beispielcode aktualisiert. – user124114

+0

Ich habe die Antwort aktualisiert, die zeigt, wie der Fehler erfasst und an next() übergeben wird. – 250R

+0

Danke @ 250R! Leider kann ich es mir nicht leisten, die Code-Logik überall mit solchen Konstrukten zu überfrachten, also werde ich mit der Lösung, mit der Matt verbunden ist, in den obigen Kommentaren gehen. – user124114

38

auszudrücken Wenn Sie wirklich alle Ausnahmen wollen fangen und einige Umgang mit anderen bieten als Wenn Sie den Node.js-Prozess beenden, müssen Sie das Ereignis uncaughtException des Knotens behandeln.

Wenn Sie darüber nachdenken, ist dies eine Knoten Sache, und keine Express-Sache, denn wenn Sie eine Ausnahme von einem beliebigen Stück Code werfen, gibt es keine Garantie, Express kann oder wird es jemals sehen, oder in einem sein Position, um es zu fangen. (Warum? Ausnahmen interagieren nicht sehr gut mit asynchronem ereignisgesteuertem Callback Code, der den Node-Stil darstellt. Exceptions durchlaufen den Aufruf-Stack, um einen catch() Block zu finden, der sich zum Zeitpunkt des Auslösens der Ausnahme befindet. Wenn myFunction etwas Arbeit verzögert zu einer Callback-Funktion, die ausgeführt wird, wenn ein Ereignis eintritt, dann zurück zur Ereignisschleife und dann, wenn diese Callback-Funktion aufgerufen wird, wird sie direkt von der Hauptereignisschleife aufgerufen, und myFunction ist nicht mehr im Call-Stack, wenn diese Callback-Funktion auslöst eine Ausnahme, auch wenn myFunction einen try/catch-Block hat, wird es die Ausnahme nicht fangen.)

Was bedeutet dies in der Praxis ist, dass, wenn Sie eine Ausnahme werfen und nicht selbst fangen und Sie tun dies in Eine Funktion, die direkt von Express aufgerufen wurde, Express kann die Exception erfassen n und rufen Sie den Fehlerhandler, den Sie installiert haben, auf, vorausgesetzt, Sie haben eine Fehlerbehandlung Middleware wie app.use(express.errorHandler()) konfiguriert. Wenn Sie jedoch dieselbe Ausnahme in einer Funktion auslösen, die als Reaktion auf ein asynchrones Ereignis aufgerufen wurde, kann Express sie nicht abfangen. (Die einzige Möglichkeit, es zu finden, ist das Abhören des globalen Knotens uncaughtException, was zuerst eine schlechte Idee wäre, weil es global ist und Sie es möglicherweise für andere Dinge verwenden müssen, und zweitens, weil Express keine Ahnung hat, welche Anfrage war verbunden mit der Ausnahme.)

Hier ist ein Beispiel.Ich füge diesen Schnipsel routenBehandlungsCode zu einem bestehenden Express App:

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

Nun, wenn ich http://localhost:3000/fail/sync in meinem Browser besuchen, Dumps der Browser einen Call-Stack (express.errorHandler in Aktion). Wenn ich jedoch in meinem Browser http://localhost:3000/fail/async aufrufe, wird der Browser verärgert (Chrome zeigt eine Meldung "Keine Daten erhalten: Fehler 324, net :: ERR_EMPTY_RESPONSE: Der Server hat die Verbindung geschlossen, ohne Daten zu senden"), weil der Node-Prozess beendet wurde , zeigt ein Backtrace auf stdout im Terminal an, wo ich es aufgerufen habe.

+5

Dies ist eine wirklich ausgezeichnete Antwort, weil es nicht nur in seiner Klarheit beleuchtet, wie Express verirrt Ausnahmen und behandelt sie mit Fehler Middleware (was ist ein unerwartetes Standardverhalten), sondern auch, weil es erklärt, wie mit 'neuen Fehler werfen (" ... ") 'in asynchronen Funktionen wird keine Fehler-Middleware auslösen und wird tatsächlich von keinem Ausnahmehandler abgefangen, der die Async-Funktion umschließt. Sie können diese Informationen nirgendwo anders finden. – fthinker

+2

Verwenden von [Domänen] (http://nodejs.org/api/domain.html) sind eine bessere Alternative zum Erfassen von 'uncaughtException'. – James

+2

Domains werden gerade veraltet. Was ist die alternative API? –

10

Um asynchrone Fehler abfangen zu können, verwende ich domain. Mit Express können Sie diesen Code versuchen:

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

Dieser Code wird Ihre asynchronen Fehler Ihre Fehlerbehandlung werden machen erfaßt und gesendet. In diesem Beispiel verwende ich den express.errorHandler, aber es funktioniert mit jedem Handler.

Weitere Informationen zur Domain: http://nodejs.org/api/domain.html

+0

Hier ist ein NPM-Paket tun Sie dies: https://www.npmjs.com/package/express-domain-middleware – pjincz

+0

beste Antwort/Lösung! – felixfbecker

+3

Das Modul 'domain' ist ausstehend. Also ich würde es nicht empfehlen. – mauvm

Verwandte Themen