Cómo manejar correctamente los errores en Express?


Estoy empezando a trabajar con Express JS y me he encontrado con un problema. No puedo encontrar la forma correcta de manejar los errores.

Por ejemplo, tengo una API de servicios web que sirve un objeto llamado "evento". Me gustaría devolver una cadena simple de "no se puede encontrar evento" cuando un usuario envía un id de evento que no se encuentra. Así es como actualmente estoy estructurando mi código:

app.get('/event/:id', function(req, res, next) {
    if (req.params.id != 1) {
        next(new Error('cannot find event ' + req.params.id));
    }

    req.send('event found!');
});

Cuando envío un id que no sea 1, el nodo se bloquea con lo siguiente salida:

http.js:527
   throw new Error("Can't set headers after they are sent.");
         ^
Error: Can't set headers after they are sent.
    at ServerResponse.<anonymous> (http.js:527:11)
    at ServerResponse.setHeader (/usr/local/kayak/node_modules/express/node_modules/connect/lib/patch.js:62:20)
    at /usr/local/kayak/node_modules/express/node_modules/connect/lib/middleware/errorHandler.js:72:19
    at [object Object].<anonymous> (fs.js:107:5)
    at [object Object].emit (events.js:61:17)
    at afterRead (fs.js:878:12)
    at wrapper (fs.js:245:17)

Por lo que puedo decir usando el nodo.js debugger, la ejecución del bloque de código continúa después de que se llama next(), lo que significa que req.send('event found!') intenta ejecutarse. No quiero que esto suceda.

La única solución que he encontrado es simplemente lanzar un new Error() en lugar de "next-ing", pero esto resulta en una página de error Express HTML predeterminada que se genera. Me gustaría un poco más de control que eso.

Me he tomado el tiempo para leer el error manejando la sección de la documentación de Express, pero no pude darle sentido.

Author: nbro, 2011-10-10

3 answers

Usted querrá revisar Express Error Handling. A partir de ahí:

app.param('userId', function(req, res, next, id) {
    User.get(id, function(err, user) {
        if (err) return next(err);
        if (!user) return next(new Error('failed to find user'));
        req.user = user;
        next();
    });
});

El punto dulce que le falta es el return next(...)

 35
Author: Chance,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-11-14 16:10:47

Eso es porque lo estás haciendo mal: ya lanzaste un Error (que será procesado por Express y devolverá una página de 500 errores para el usuario o algo así) pero también estás tratando de enviar tu propia respuesta al cliente: res. send ('evento encontrado!');

Realmente debería revisar la guía Rápida sobre el Manejo de errores aquí: http://expressjs.com/guide/error-handling.html

Lo que haría en tu ejemplo es:

function NotFound(msg){
  this.name = 'NotFound';
  Error.call(this, msg);
  Error.captureStackTrace(this, arguments.callee);
} 

app.get('/event/:id', function(req, res, next){
  if (req.params.id != 1) {
    throw new NotFound('Cannot find event ' + req.params.id);
  } else {
    res.send('event found!');
  }
});

app.error(function(err, req, res, next){
    if (err instanceof NotFound) {
        res.render('404.ejs');
    } else {
        next(err);
    }
});
 19
Author: alessioalex,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-09-07 09:21:08

Tienes un par de problemas en tu código:

  • Al responder al cliente, es necesario utilizar el objeto response (res en lugar de req).

  • Al enviar un error a next, debe retorno, así que el resto de la función no se ejecuta.

Aquí está su código después de corregir esos errores:

app.get('/event/:id', function(req, res, next) {
    if (req.params.id != 1) {
        return next(new Error('cannot find event ' + req.params.id));
    }

    res.send('event found!'); // use res.send (NOT req.send)
}); 
 10
Author: evilcelery,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-11-14 16:16:20