Empresas
Empleos
  • Sobre nosotros
  • Soluciones
    • Publicación de vacantes
      Publica tu vacante y recibe candidatos calificados en 48h.
    • Evaluación de candidatos
      500+ pruebas técnicas y psicológicas, más anti-fraude.
    • Headhunting
      Búsqueda ejecutiva a la medida de principio a fin.
    • Nómina + EOR
      Dispersión de nómina y EOR en más de 15 países de LATAM.
  • Precios
  • Empleos

0

171
Vistas
Express Error en el manejo de middleware para producción y desarrollo

Estoy tratando de hacer que el registro de errores de producción sea el predeterminado y mostrarle al usuario las cosas adicionales solo si la environment variable es development . Estoy tratando de hacer esto de la siguiente manera a continuación, pero recibo un mensaje que dice Cannot set headers after they are sent to the client .

 const ErrorClass = require('../routes/utils/ErrorClass'); const prodDBCastError = err => { const message = `Invalid ${err.path}: ${err.value}`; return new ErrorClass(message, 400); }; const prodDBDuplicateFieldsError = err => { const value = err.errmsg.match(/(["'])(\\?.)*?\1/)[0]; const message = `Duplicate field value: ${value}.`; return new ErrorClass(message, 400); }; const prodDBDValidationError = err => { const errors = Object.values(err.errors).map(el => el.message); const message = `Invalid input data. ${errors.join('. ')}`; return new ErrorClass(message, 400); }; const handleBadRequestDB = err => { const errors = err.message; const message = `Fixes: ${errors}`; return new ErrorClass(message, 400); }; const sendProdError = (err, res) => { if (err.isOperationalError){ res.status(err.status).json({ status: err.status, message: err.message, }); } else { res.status(500).json({ status: 'error', message: 'Server Issue.', }); } }; const sendVerboseDevError = (err, res) => { logger.error(err); err.status = err.status || 500; res.status(err.status).json({ status: err.status, name: err.name, path: err.path, errors: err.errors, message: err.message, stack: err.stack, }); }; module.exports = (err, req, res, next) => { if (process.env.APP_ENV === 'development'){ sendVerboseDevError(err, res); } if (err.name === 'CastError') {err = prodDBCastError(err);} if (err.name === 'MongoError') {err = prodDBDuplicateFieldsError(err);} if (err.name === 'ValidationError') {err = prodDBDValidationError(err);} if (err.name === 'Bad Request') {err = handleBadRequestDB(err);} sendProdError(err, res); };

Así es como se ve mi ErrorClass:

 class ErrorClass extends Error { constructor(message, status) { super(message); this.status = status; this.isOperationalError = true; Error.captureStackTrace(this, this.constructor); } } module.exports = ErrorClass;
over 4 years ago · Santiago Trujillo
3 Respuestas
Responde la pregunta

0

Te recomendaría cambiar tu código así.

Primero, evita llamar a res.json varias veces y también solo verifica si la aplicación se ejecuta en modo de desarrollo una vez. No hay necesidad de verificarlo con cada solicitud.

 var devHandler = (err, req, res, next) => { logger.error(err); err.status = err.status || 500; res.status(err.status).json({ status: err.status, name: err.name, path: err.path, errors: err.errors, message: err.message, stack: err.stack, }); }; var prodHandler = (err, req, res, next) => { if (err.name === 'CastError') {err = prodDBCastError(err);} if (err.name === 'MongoError') {err = prodDBDuplicateFieldsError(err);} if (err.name === 'ValidationError') {err = prodDBDValidationError(err);} if (err.name === 'Bad Request') {err = handleBadRequestDB(err);} if (err.isOperationalError){ res.status(err.status).json({ status: err.status, message: err.message, }); } else { res.status(500).json({ status: 'error', message: 'Server Issue.', }); } }; module.exports = process.env.APP_ENV === 'development' ? devHandler : prodHandler;
over 4 years ago · Santiago Trujillo Denunciar

0

Esto se debe a que está intentando enviar datos desde sendProdError después de enviar datos desde sendVerboseDevError . res.json está enviando el json al cliente.

La razón detrás de esto se explica aquí https://stackoverflow.com/a/7086621/2232902

El objeto res en Express es una subclase de http.ServerResponse de Node.js (lea la fuente de http.js). Puede llamar a res.setHeader(nombre, valor) con la frecuencia que desee hasta que llame a res.writeHead(statusCode). Después de writeHead, los encabezados se integran y solo puede llamar a res.write(data) y finalmente a res.end(data)

Le recomendaría modificar sendProdError y sendVerboseDevError en constructProdError y constructVerboseDevError y luego enviar desde el mismo punto en el código.

referencia: https://stackoverflow.com/a/733858/2232902

over 4 years ago · Santiago Trujillo Denunciar

0

Creo que el problema aquí es con las condiciones múltiples. Si la primera condición se cumple, se ejecutará la función "sendVerboseDevError". Que tiene el siguiente código

 res.status(err.status).json({ status: err.status, name: err.name, path: err.path, errors: err.errors, message: err.message, stack: err.stack, });

después de esta función, se establecerá el encabezado de respuesta. Luego, el flujo si va al resto de las condiciones si las condiciones son verdaderas y luego nuevamente se llama a otra función que está tratando de establecer la respuesta nuevamente. Es por eso que recibe el error "No se pueden configurar los encabezados después de enviarlos al cliente". Debe llamar al método "siguiente ()" después de configurar la respuesta. Por lo tanto, debe agregar el método "siguiente ()" en la parte inferior de cada condición.

algo como

 module.exports = (err, req, res, next) => { if (process.env.APP_ENV === 'development'){ sendVerboseDevError(err, res); next(); } if (err.name === 'CastError') { err = prodDBCastError(err); next(); } if (err.name === 'MongoError') { err = prodDBDuplicateFieldsError(err); next(); } if (err.name === 'ValidationError') { err = prodDBDValidationError(err); next(); } if (err.name === 'Bad Request') { err = handleBadRequestDB(err); next(); } sendProdError(err, res); next(); };

la siguiente función terminará la llamada API y devolverá la respuesta y evitará que establezca la respuesta nuevamente después de que cualquier función ejecutada antes de la actual haya establecido la respuesta.

PD: También puede llamar a la función "res.end()" en lugar de "next()".

over 4 years ago · Santiago Trujillo Denunciar
Responde la pregunta
Encuentra empleos remotos

¡Descubre la nueva forma de encontrar empleo!

Top de empleos
Top categorías de empleo
Empresas
Publicar vacante Precios Comercial
Legal
Términos y condiciones Política de privacidad
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomiéndame algunas ofertas
Necesito ayuda