node.js - res.send() 不发送当前响应,而是保留最后一个响应

标签 node.js mongodb express

这是我在index.js 中的一些代码。它等待人们访问 url.com/proxy,然后加载我的代理页面,这实际上只是一个发回电子邮件和代码的表单。从我的 MongoDB 数据库中,我使用代码获取用户订单,其中包含我需要的一些信息(例如产品和他们试图获取的消息)。由于某种原因,它似乎在获取此信息之前做出响应,然后在下次提交表单时保留它。

我的 res.send(product + '\n' + message) 中的换行符也不起作用,但这现在不是什么大问题。

但是..例如,我第一次填写表格时会得到空白回复。第二次,我将得到对第一个表格填写的任何内容的回复,然后第三次我将得到第二个回复。我对网络开发相当陌生,感觉我正在做一些明显错误的事情,但似乎无法弄清楚。任何帮助将不胜感激,谢谢。

   app.get('/proxy', function(req,res){
        res.sendFile(__dirname+ "/views/proxy.html");
    });

    var message = "";
    var product = "";

    app.post('/getMessage', function(req,res)
    {
        returnMsg(req.body.user.code, req.body.user.email);
        //res.setHeader('Content-Type', 'text/plain');
        res.send(product + "\n" + message);
    });

    function returnMsg(code, email){
        MongoClient.connect(url, function(err, db){
            var cursor = db.collection('Orders').find( { "order_id" : Number(code) })
            cursor.each(function(err, doc){
                assert.equal(err, null);
                if (doc!= null)
                {
                        message = doc["message"];
                        product = doc["product"];
                }
                else {
                        console.log("wtf");
                    // error code here
                }
            });
            console.log(email + " + " + message);
            var document = {
                    "Email" : email,
                    "Message" : message
            }
            db.collection("Users").insertOne(document);
            db.close();
        });
    }

最佳答案

您需要大量阅读有关 Node.js 中的异步编程工作的内容。此代码存在严重的设计问题:

  1. 您正在使用模块级变量而不是请求级变量。
  2. 您没有正确处理异步响应。

所有这些都会导致服务器根本无法正常工作。您已经发现了问题之一。您的异步响应在发送响应后完成,因此您最终会发送之前保存的响应而不是当前的响应。此外,如果多个用户正在使用您的服务器,他们的响应将相互影响。

这里的核心设计原则是,首先您需要学习如何使用异步操作进行编程。任何使用异步响应并希望将该值返回给调用者的函数都需要接受回调并通过回调传递异步值,或者返回一个 promise 并通过已解析的 promise 返回该值。然后,调用者需要使用该回调或 promise 在异步值可用时获取异步值,然后仅发送响应。

此外,与请求关联的所有数据都需要保留在请求句柄或请求对象的“内部”,而不是在任何模块级别或全局变量中。这可以防止一个用户的请求干扰另一用户的请求。

要了解如何从包含异步操作的函数返回值,请参阅 How do I return the response from an asynchronous call? .

<小时/>

您的代码中最终发生的是以下事件序列:

  1. 收到 /getMessage 的请求
  2. 您调用returnMsg()
  3. returnMsg 发起与数据库的连接,然后返回
  4. 您的请求处理程序调用 res.send()message 中之前的内容一起使用和product变量。
  5. 然后,过了一段时间,数据库连接完成,您调用 db.collection().find()然后迭代 cursor .
    6/一段时间后,光标迭代得到第一个结果,您将其放入 message 中和product变量(这些值一直保留在下一个请求到来之前)。

在弄清楚你的代码应该如何实际工作时,你的逻辑中有一些不清楚的地方。您正在分配 messageproduct cursor.each()里面。自 cursor.each()是一个可以运行多次迭代的循环,其值为 messageproduct你真的想在 res.send() 中使用吗? ?

<小时/>

假设您想要最后一个 messageproduct来自您的cursor.each()的值(value)循环,你可以这样做:

app.post('/getMessage', function(req, res) {
    returnMsg(req.body.user.code, req.body.user.email, function(err, message, product) {
        if (err) {
            // send some meaningful error response
            res.status(500).end();
        } else {
            res.send(product + "\n" + message);
        }
    });
});

function returnMsg(code, email, callback) {
    let callbackCalled = false;
    MongoClient.connect(url, function(err, db) {
        if (err) {
            return callback(err);
        }
        var cursor = db.collection('Orders').find({
            "order_id": Number(code)
        });
        var message = "";
        var product = "";

        cursor.each(function(err, doc) {
            if (err) {
                if (!callbackCalled) {
                    callback(err);
                    callbackCalled = true;
                }
            } else {
                if (doc != null) {
                    message = doc["message"];
                    product = doc["product"];
                } else {
                    console.log("wtf");
                    // error code here
                }
            }
        });
        if (message) {
            console.log(email + " + " + message);
            var document = {
                "Email": email,
                "Message": message
            }
            db.collection("Users").insertOne(document);
        }
        db.close();
        if (!callbackCalled) {
            callback(null, message, product);
        }
    });
}

就个人而言,我会使用 Promise 并在数据库中使用 Promise 接口(interface),而不是回调。

<小时/>

此代码仍然只是概念性的,因为它还有您需要处理的其他问题,例如:

  1. 正确的错误处理在很大程度上仍未完成。
  2. 您实际上并不是在等待像 insert.One() 这样的事情在继续之前先完成。

关于node.js - res.send() 不发送当前响应,而是保留最后一个响应,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44809316/

相关文章:

javascript - discord.js v14 中的 setPresence 事件类型只能设置为 "PLAYING"

node.js - jade 中变量内的长字符串

node.js - 在 sequelize 中定义自定义验证

javascript - 将数组作为元素添加到javascript中的数组

node.js - ## Node 纤维有问题##

c# - Web api 2 和 Mongodb v2 将示例代码迁移到使用驱动程序版本 2

java - 使用 Java 在 mongodb 中插入 SQL 日期作为 ISODate

javascript - 是否可以将元素插入 MongoDB 文档中的数组中间?

node.js - 如何使用nodejs和mongoose从mongodb集合中删除数据

node.js - 在Express中渲染jade时包含其他文件的内容吗?