2012-04-30 10 views
22

Revisé la documentación de Express, y the part describing error handling es completamente opaco para mí.¿Cómo manejar las excepciones de código en node.js?

Pensé que el app al que se refieren es una instancia createServer(), ¿verdad? Pero no tengo ni idea de cómo detener node.js de explotar el proceso de la aplicación cuando se produce una excepción durante el manejo de una solicitud.

No necesito nada realmente sofisticado; Solo quiero devolver un estado de 500, más una respuesta por lo demás vacía, siempre que haya una excepción. El proceso de nodo no debe terminar solo porque hubo una excepción no detectada en alguna parte.

¿Hay un ejemplo simple de cómo lograr esto?


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

se bloquea la aplicación completa, la producción de rastreo

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

'simplemente porque no había una excepción no capturada somewhere.' El proceso *** *** va a morir si hay un * * excepción no detectada. Si no desea que finalice cuando ocurre una excepción, capture la excepción y devuelva el error 500. – Chad

+2

Puede que le interese la forma no expresa: http://stackoverflow.com/questions/4213351/make-node-js-not-exit-on-error – Matt

+0

Excelente, muchas gracias @Matt! – user124114

Respuesta

2

Puede utilizar el gestor de errores por defecto que expresan usos, que en realidad es 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); 

actualización Para su código, en realidad se necesita para capturar el error y pasarlo a expresarse como esto

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

Su ejemplo funciona (después de agregar 'var express = require ('express');'), pero desafortunadamente cuando hago lo mismo en mi código, todavía cuelga el proceso. He actualizado la pregunta con código de muestra. – user124114

+0

He actualizado la respuesta que muestra cómo capturar el error y pasarlo a express usando next(). – 250R

+0

¡Gracias @ 250R! Lamentablemente, no puedo permitirme desperdiciar la lógica del código en todas partes con tales constructos, así que iré con la solución a la que Matt se vinculó, en los comentarios anteriores. – user124114

38

Si realmente se desea capturar todas las excepciones y proporcionar alguna otra manipulación de al salir del proceso Node.js, necesita manejar el evento uncaughtException de Node.

Si lo piensas bien, esto es algo de Nodo, y no de Expreso, porque si lanzas una excepción desde un código arbitrario, no hay garantía de que Express lo pueda ver o lo vea nunca, o estar en una posición para atraparlo. Las excepciones no interactúan muy bien con el código de llamada por evento asíncrono que es el estilo de Nodo. ​​Las excepciones viajan por la pila de llamadas para encontrar un bloque catch() que está en el alcance en el momento de la excepción. Si myFunction difiere algún trabajo a una función de devolución de llamada que se ejecuta cuando ocurre algún evento, luego vuelve al bucle de evento, luego cuando se invoca esa función de devolución de llamada, se invoca directamente desde el bucle de evento principal y myFunction ya no está en la pila de llamadas; una excepción, incluso si myFunction tiene un bloque try/catch, no va a captar la excepción.)

Lo que esto significa en la práctica es que si lanza una excepción y no la atrapa usted mismo y lo hace en una función que fue llamada directamente por Express, Express puede atrapar la exceptio n y llame al controlador de errores que ha instalado, suponiendo que haya configurado algún middleware de manejo de errores como app.use(express.errorHandler()). Pero si lanza la misma excepción en una función que fue llamada en respuesta a un evento asincrónico, Express no podrá detectarla. (La única forma en que podría detectarlo es escuchando el evento Nodo uncaughtException global, que sería una mala idea primero porque es global y es posible que deba usarlo para otras cosas, y segundo porque Express no tendrá idea de qué solicitud fue asociado con la excepción.)

Aquí hay un ejemplo.Añado este fragmento de código de ruta de manipulación a una aplicación existente expreso:

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

Ahora si me visita http://localhost:3000/fail/sync en mi navegador, el navegador vertederos de una pila de llamadas (mostrando express.errorHandler en acción). Si visito http://localhost:3000/fail/async en mi navegador, sin embargo, el navegador se enoja (Chrome muestra un mensaje "No hay datos recibidos: Error 324, net :: ERR_EMPTY_RESPONSE: El servidor cerró la conexión sin enviar ningún dato", porque el proceso Nodo ha salido , que muestra una traza inversa en stdout en la terminal donde lo invoqué.

+5

Esta es una respuesta realmente excelente porque no solo esclarece la claridad de cómo las capturas extravia las excepciones y las maneja con middleware de error (que es un comportamiento predeterminado inesperado), sino también porque explica cómo usar 'throw new Error (" ... ") 'en las funciones asíncronas no activará el middleware de errores y, de hecho, ni siquiera será capturado por ningún controlador de excepción que ajuste la función asíncrona. No puedes encontrar esta información en ningún otro lado. – fthinker

+2

El uso de [dominios] (http://nodejs.org/api/domain.html) es una mejor alternativa que la captura de 'uncaughtException'. – James

+2

Los dominios están en proceso de desaprobación. ¿Cuál es la API alternativa? –

10

Para poder detectar errores asincrónicos, uso el dominio. Con Express puede probar este código:

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

Este código hará que se capturó el error asíncrono y se envía al controlador de errores. En este ejemplo, utilizo express.errorHandler, pero funciona con cualquier controlador.

Para obtener más información acerca de dominio: http://nodejs.org/api/domain.html

+0

Aquí hay un paquete npm para hacer esto: https://www.npmjs.com/package/express-domain-middleware – pjincz

+0

mejor respuesta/solución! – felixfbecker

+3

El módulo 'dominio' está pendiente de desactivación. Entonces no recomendaría usarlo. – mauvm

Cuestiones relacionadas