res.send()没有发送当前响应,而是保留最后一个

时间:2017-06-28 17:43:28

标签: node.js mongodb express

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

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

但是..例如,我第一次填写表格时得到空白回复。第二次,我将得到对第一种形式填写的任何内容的响应,然后第三次生病得到第二次响应。我对Web开发很新,觉得我做的事情显然是错的,但似乎无法弄明白。任何帮助将不胜感激,谢谢。

   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();
        });
    }

1 个答案:

答案 0 :(得分:1)

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

  1. 您正在使用模块级变量而不是请求级变量。
  2. 您没有正确处理异步响应。
  3. 所有这些都使服务器无法正常工作。你已经发现了其中一个问题。您的异步响应在您发送响应后完成,因此您最终发送的是先前保存的响应,而不是当前保存的响应。此外,如果多个用户正在使用您的服务器,他们的回复将会互相攻击。

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

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

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

    您的代码中最终发生的是这一系列事件:

    1. /getMessage
    2. 的传入请求
    3. 您致电returnMsg()
    4. returnMsg启动与数据库的连接,然后返回
    5. 您的请求处理程序使用res.send()message变量中的任何内容调用product
    6. 然后,稍后,数据库连接完成,您调用db.collection().find()然后重复cursor
      6 /稍后,光标迭代会将第一个结果存入您的messageproduct变量(这些值会一直存在,直到下一个请求进入)。
    7. 在计算代码实际工作方式时,有一些关于你的逻辑的事情尚不清楚。您在message内分配productcursor.each()。由于cursor.each()是一个可以运行多次迭代的循环,messageproduct的值实际上是否要在res.send()中使用?

      假设您想要message循环中的最后productcursor.each()值,您可以这样做:

      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);
              }
          });
      }
      

      就个人而言,我会使用promises并在数据库中使用promise接口而不是回调。

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

      1. 正确的错误处理仍未完成。
      2. 在继续之前,您实际上并没有等待insert.One()之类的事情完成。