sql >> Base de Datos >  >> NoSQL >> MongoDB

¿Por qué recibo No se pueden establecer encabezados después de que se envían al error del cliente en Nodejs?

Justo aquí:

Post.find({}, function(err, docs) {
    if (docs.length == 0)
        return res.send({ message: "No posts" });

Si alcanza esa condición de docs.length == 0 , luego enviará una respuesta a la solicitud. Pero, tu return SOLO regresa de Post.find() llamar de vuelta. No regresa de tus trendingposts() función.

Entonces, mientras tanto, esa función continúa ejecutándose y eventualmente llega a este código:

var mysort = { score: -1 };
Post.find({})
    .populate("postedBy")
    .populate("comments.postedBy")
    .populate("comments.incomments.postedBy")
    .populate("comments.likes")
    .sort(mysort)
    .limit(10)
    .exec((er, result) => {

        res.json(result);
    });

Donde luego envía otra respuesta a la misma solicitud. Eso es lo que desencadena el error Cannot set headers after they are sent to the client que ves.

Hay muchas formas diferentes de evitar esto, pero probablemente todas estén relacionadas con la forma en que generalmente limpiaría esta función. De la forma en que está escrito ahora, esencialmente inicia dos rutas de código asincrónico completamente separadas. Ambos comienzan con Post.find({}) e ir desde allí. Cada uno se ejecuta en paralelo y ninguno tiene idea de lo que está haciendo la otra ruta de código. Como tal, no tiene una forma concreta de enviar una respuesta de uno, pero no de ambos.

Entonces, la forma de limpiar esto es probablemente no tener dos rutas de código asincrónico completamente separadas. Necesitas coordinarlos de alguna manera. En casi todos los casos aquí, querrá cambiar a la interfaz de promesa de su base de datos, ya que eso le dará muchas más opciones para administrar su flujo de control. Por ejemplo, si por motivos de rendimiento desea tener dos operaciones asincrónicas paralelas a la vez, con promesas, puede usar Promise.all() o Promise.allSettled() para monitorear ambos y saber cuándo están listos y luego, con ambos resultados en la mano, decidir qué respuesta enviar.

O, si desea secuenciarlos, puede usar async/await para secuenciar fácilmente las dos operaciones y luego cuando haces un return , en realidad regresará de la función de nivel superior y detendrá el flujo de control adicional.

Si desea seguir con la interfaz de devolución de llamada a su base de datos, entonces probablemente tendrá que anidar la segunda operación en la primera opción para no iniciar la segunda operación si va a hacer res.send({ message: "No posts" }) .