Traducir esta página

Manejo de errores

Error Handling refers to how Express catches and processes errors that occur both synchronously and asynchronously. Express viene con un manejador de error predeterminado , así que no necesitas escribir el tuyo propio para empezar.

Errores de captura

Es importante asegurarse de que Express capture todos los errores que ocurren mientras ejecuta los manejadores de rutas y el middleware.

Los errores que ocurren en el código sincrónico dentro de los manejadores de rutas y middleware no requieren trabajo extra. Si el código sincrónico arroja un error, entonces Express hará capturarlo y procesarlo. Por ejemplo:

app.get('/', (req, res) => {
throw new Error('BROKEN'); // Express will catch this on its own.
});

Para los errores devueltos por funciones asincrónicas invocadas por los manejadores de rutas y middleware, debes pasarlos a la función next(), donde Express las capturará y procesará . Por ejemplo:

app.get('/', (req, res, next) => {
fs.readFile('/file-does-not-exist', (err, data) => {
if (err) {
next(err); // Pass errors to Express.
} else {
res.send(data);
}
});
});

A partir de Express 5, manejadores de rutas y middleware que devuelven una Promise llamará automáticamente a next(value) cuando rechacen o lancen un error. Por ejemplo:

app.get('/user/:id', async (req, res, next) => {
const user = await getUserById(req.params.id);
res.send(user);
});

Si getUserById arroja un error o rechaza, next será llamado con el error arrojado o el valor rechazado. Si no se proporciona ningún valor rechazado, next será llamado con un objeto de Error predeterminado proporcionado por el enrutador Express.

If you pass anything to the next() function (except the string 'route'), Express regards the current request as being an error and will skip any remaining non-error handling routing and middleware functions.

Si la devolución de llamada en una secuencia no proporciona datos, sólo errores, puede simplificar este código de la siguiente manera:

app.get('/', [
function (req, res, next) {
fs.writeFile('/inaccessible-path', 'data', next);
},
function (req, res) {
res.send('OK');
},
]);

En el ejemplo anterior, next es proporcionado como el callback para fs.writeFile, que es llamado con o sin errores. Si no hay error, se ejecuta el segundo manejador , de lo contrario Express catches y procesa el error.

Debe capturar errores que ocurren en código asíncrono invocado por manejadores de ruta o un middleware y pasarlos a Express para su procesamiento. Por ejemplo:

app.get('/', (req, res, next) => {
setTimeout(() => {
try {
throw new Error('BROKEN');
} catch (err) {
next(err);
}
}, 100);
});

El ejemplo anterior utiliza un bloque try...catch para capturar errores en el código asincrónico y pasarlos a Express. Si el bloque try...catch fuera omitido, Express no capturaría el error ya que no es parte del código de manejador sincrónico.

Usa promesas para evitar la sobrecarga del bloque “intentar…atrapar” o al usar funciones que devuelven promesas. Por ejemplo:

app.get('/', (req, res, next) => {
Promise.resolve()
.then(() => {
throw new Error('BROKEN');
})
.catch(next); // Errors will be passed to Express.
});

Since promises automatically catch both synchronous errors and rejected promises, you can simply provide next as the final catch handler and Express will catch errors, because the catch handler is given the error as the first argument.

También podría utilizar una cadena de manejadores para depender de la captura de errores sincrónicos , reduciendo el código asincrónico a algo trivial. Por ejemplo:

app.get('/', [
function (req, res, next) {
fs.readFile('/maybe-valid-file', 'utf-8', (err, data) => {
res.locals.data = data;
next(err);
});
},
function (req, res) {
res.locals.data = res.locals.data.split(',')[1];
res.send(res.locals.data);
},
]);

El ejemplo anterior tiene un par de declaraciones triviales de la llamada readFile . Si readFile causa un error, entonces pasa el error a Express, de lo contrario regresa rápidamente al mundo del manejo sincrónico de errores en el siguiente manejador en la cadena. Luego, el ejemplo anterior intenta procesar los datos. Si esto falla, entonces el gestor de errores sincrónico lo capturará. Si hubiera hecho este procesamiento dentro de el callback readFile, entonces la aplicación podría salir y los manejadores de error Express no se ejecutarían.

Whichever method you use, if you want Express error handlers to be called in and the application to survive, you must ensure that Express receives the error.

El gestor de errores por defecto

Express viene con un gestor de errores integrado que se encarga de cualquier error que pueda encontrarse en la aplicación. Esta función middleware por defecto se añade al final de la pila de funciones de middleware.

Si pasas un error a next() y no lo gestionas en un controlador error personalizado, será manejado por el gestor de errores integrado; el error será escrito al cliente con el stack trace. El stack trace no está incluido en el entorno de producción.

Note

Establece la variable de entorno NODE_ENV a production, para ejecutar la aplicación en el modo de producción.

When an error is written, the following information is added to the response:

  • El res.statusCode se establece desde err.status (o err.statusCode). Si este valor está fuera del rango 4xx o 5xx, se establecerá a 500.
  • El res.statusMessage se establece de acuerdo al código de estado.
  • El cuerpo será el HTML del mensaje del código de estado cuando en el entorno de producción, de lo contrario será err.stack.
  • Cualquier cabecera especificada en un objeto err.headers.

Si llama a next() con un error después de haber comenzado a escribir la respuesta (por ejemplo, si encuentras un error al transmitir la respuesta al cliente), el gestor de errores Express por defecto cierra la conexión y falla la solicitud.

Así que cuando añada un manejador de errores personalizado, debe delegar a el manejador de errores predeterminado Express cuando los encabezados ya han sido enviados al cliente:

function errorHandler(err, req, res, next) {
if (res.headersSent) {
return next(err);
}
res.status(500);
res.render('error', { error: err });
}

Tenga en cuenta que el manejador de errores por defecto puede activarse si llama a next() con un error en su código más de una vez, incluso si el middleware está configurado para manejar errores personalizados.

Otro middleware de manejo de error se puede encontrar en Express middleware.

Manejadores de errores escritos

Define las funciones de middleware de la misma manera que otras funciones de middleware, excepto las funciones de manejo de errores tienen cuatro argumentos en lugar de tres: (err, req, res, next). Por ejemplo:

app.use((err, req, res, next) => {
console.error(err.stack);
res.status(500).send('Something broke!');
});

Usted define middleware manejado por errores últimamente, después de otras app.use() y llamadas de rutas; por ejemplo:

const bodyParser = require('body-parser');
const methodOverride = require('method-override');
app.use(
bodyParser.urlencoded({
extended: true,
})
);
app.use(bodyParser.json());
app.use(methodOverride());
app.use((err, req, res, next) => {
// logic
});

Las respuestas desde dentro de una función middleware pueden estar en cualquier formato, como una página de error HTML, un mensaje simple, o una cadena JSON.

For organizational (and higher-level framework) purposes, you can define several error-handling middleware functions, much as you would with regular middleware functions. Por ejemplo, para definir un manejador de errores para las solicitudes realizadas usando XHR y las que no tienen:

const bodyParser = require('body-parser');
const methodOverride = require('method-override');
app.use(
bodyParser.urlencoded({
extended: true,
})
);
app.use(bodyParser.json());
app.use(methodOverride());
app.use(logErrors);
app.use(clientErrorHandler);
app.use(errorHandler);

En este ejemplo, el genérico logErrors podría escribir una solicitud y información de error a stderr, por ejemplo:

function logErrors(err, req, res, next) {
console.error(err.stack);
next(err);
}

También en este ejemplo, clientErrorHandler se define de la siguiente manera; en este caso, el error se pasa explícitamente al siguiente.

Tenga en cuenta que cuando no llama “siguiente” en una función de manejo de errores, usted es responsable de escribir (y terminar) la respuesta. De lo contrario, esas solicitudes se “colgarán” y no serán elegibles para la recolección de basura.

function clientErrorHandler(err, req, res, next) {
if (req.xhr) {
res.status(500).send({ error: 'Something failed!' });
} else {
next(err);
}
}

Implementa la función “catch-all” errorHandler como sigue (por ejemplo):

function errorHandler(err, req, res, next) {
res.status(500);
res.render('error', { error: err });
}

Si tiene un manejador de ruta con múltiples funciones de callback, puede utilizar el parámetro route para saltar al siguiente manejador de ruta. Por ejemplo:

app.get(
'/a_route_behind_paywall',
(req, res, next) => {
if (!req.user.hasPaid) {
// continue handling this request
next('route');
} else {
next();
}
},
(req, res, next) => {
PaidContent.find((err, doc) => {
if (err) return next(err);
res.json(doc);
});
}
);

En este ejemplo, el manejador getPaidContent se omitirá pero cualquier manejador restante en app para /a_route_behind_paywall continuaría siendo ejecutado.

Note

Las llamadas a next() y next(err) indican que el controlador actual está completo y en qué estado. next(err) omitirá todos los manejadores restantes en la cadena, excepto aquellos que están configurados a errores de manejo como se describe arriba.