Manejo de errores en Express

El manejo de errores en Express se refiere a algo que maneja o procesa los errores que pueden surgir al ejecutar cualquier código síncrono o código asíncrono.

¿Qué entendemos por código síncrono o asíncrono?
Muchas veces, sucede que una operación comienza a ejecutarse pero, por alguna razón, enfrenta algún retraso antes de completarse. Los ejemplos comunes de tales operaciones son requests HTTP como requests AJAX , funciones como setTimeout , etc. Estas operaciones comienzan y luego finalizan cuando regresa la respuesta o cuando finaliza el temporizador. Mientras la computadora espera a que se completen estas operaciones, continúa ocupándose de las siguientes líneas de código. Se mantiene ocupado, pero esto genera un desafío importante: cualquier código que dependa de un código asíncrono anterior podría ejecutarse antes de que se complete el código asíncrono , lo que significa errores. Echa un vistazo a continuación-

var data = makeAsyncRequest();
  
// Data is undefined
console.log("Data is " + data);

 
Podemos decir que, cuando ejecutamos algo de forma síncrona, esperamos a que termine antes de pasar a otra tarea. Cuando ejecutamos algo de forma asíncrona, podemos pasar a otra tarea antes de que finalice. El problema anterior se resuelve usando callbacks , módulos de middleware o usando la promesa moderna y la espera.

Captura de errores en Express

  • Si el código síncrono que tiene controladores de ruta y middleware arroja algún error, entonces, sin ningún esfuerzo ni trabajo adicional, Express lo resuelve capturando y procesando el error sin requerir nuestro consentimiento. Eche un vistazo al siguiente código –

    app.get('/', function (req, res) {
        
        // Express catches this on its own
        throw new Error('Died')
     })
  • Si un controlador de ruta y un middleware invocan una función asíncrona que a su vez produce algunos errores, entonces tenemos que pasar explícitamente el error a la función next(), donde Express los detectará y procesará. La siguiente ilustración le ayudará a comprender

    app.get('/', function (req, res, next) {
      fs.readFile('/file-is-not-available'
            function (err, data) {
        if (err) {
      
          // Passing errors to 
          // Express explicitly
          next(err) 
        } else {
          res.send(data)
        }
      })
    })
  • Los controladores de ruta y los middlewares que devuelven una Promesa llamarán al siguiente (valor) automáticamente cuando rechacen o arrojen un error.

    app.get('/user/:id', async function (req, res, next) { 
      
        // Async keyword tells that it is
        // an asynchronous function
        var user = await getUserById(req.params.id)    
        res.send(user)
    })

    La palabra clave await se puede usar para indicar que la función que sigue devolverá una promesa, que debe esperarse antes de ejecutar cualquier otro código dependiente. ‘await’ solo se puede usar dentro de una función asíncrona.
    Next (siguiente) se llamará con el error arrojado o el valor rechazado en caso de que getUserById arroje un error o lo rechace. Si no se proporciona ningún valor rechazado, se llamará a next con un objeto de error predeterminado proporcionado por el enrutador Express. Si pasamos algo a la función next() (excepto la string ‘ruta’), Express considera que la solicitud actual es un error y omitirá las funciones restantes de enrutamiento y middleware que no manejan errores.

  • Si una devolución de llamada dada en una secuencia no proporciona datos y solo errores, entonces el código se puede simplificar como:

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

    En el código anterior, next se proporciona como devolución de llamada que se ejecuta sin importar si aparecen errores o no. Si no hay ningún error, el segundo controlador también se ejecuta; de lo contrario, express solo detecta y procesa el error.

    Ahora, mira el siguiente ejemplo: 

    app.get('/', function (req, res, next) {
      setTimeout(function () {
        try {
          throw new Error('Died')
        } catch (err) {
          next(err)
        }
      }, 100)
    })
  • Como sabemos, si un controlador de ruta y un middleware invocan una función asíncrona que a su vez produce algunos errores, entonces tenemos que pasar explícitamente el error a la función next(), donde Express los detectará y procesará. Sin embargo, en el código anterior, el error no es parte del código sincrónico, por lo que no podemos simplemente pasarlo a la siguiente función. Primero debemos arrojar los errores, detectar los errores generados por el código asíncrono y luego pasarlo al Express. Para esto, necesitamos usar el bloque try..catch para atraparlos. Si no desea usar Try and Catch, simplemente use las promesas como se muestra a continuación:

    app.get('/', function (req, res, next) {
      Promise.resolve().then(function () {
        throw new Error('Died')
      
      // Errors will be passed to Express
      }).catch(next)
    })
  • Controladores de errores predeterminados: siguiente

    Cuando se escribe un error, la siguiente información se agrega automáticamente a la respuesta:

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

    Si llama a next() con un error después de haber comenzado a escribir la respuesta (por ejemplo, si encuentra un error mientras transmite la respuesta al cliente), el controlador de errores predeterminado de Express cierra la conexión y falla la solicitud.

    Entonces, cuando agrega un controlador de errores personalizado, debe delegar al controlador de errores Express predeterminado, cuando los encabezados ya se han enviado al cliente:

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

    ¿Cómo escribir controladores de errores?

    (err, req, res, siguiente). Por ejemplo – 

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

    app.get('/', (req, res, next) => {
     req.foo = true;
      setTimeout(() => {
        try {
          throw new Error('error');
        }
        catch (ex) {
          next(ex);
        }
      })
    });
    app.use((err, req, res, next) => {
      if (req.foo) {
        res.status(500).send('Fail!');
      }
      else {
        next(err);
      }
    })
    app.use((err, req, res, next) => {
      res.status(500).send('Error!')
    })

Publicación traducida automáticamente

Artículo escrito por ayush_upadhyay y traducido por Barcelona Geeks. The original can be accessed here. Licence: CCBY-SA

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *