NodeJS,Express,MySQL - 发送后不能设置标头

时间:2016-07-28 19:15:25

标签: javascript mysql node.js express

我尝试使用Express开发NodeJS应用程序。 这是我的代码

app.post('/open', checkStatus, function(req, res) {
  if (req.error) {
    console.log(req.log);
    return res.json(req.error);
  }

  console.log(currentDate() + colors.gray('>> ') + colors.bold(colors.cyan(req.method)) + ' ' + colors.green('200') + ' ' + req.url);

  var data = req.body;

  status.door.isOpening = true;

  setUser(data, function() {
    setOpening(data, function() {
      openTheDoorPlease(data, function(response, log) {
        if (status.door.isOpening) {
          status.door.isOpening = false;
          console.log(log);
          return res.json(response);
        }
      });
    });
  });
});

这里是错误

throw err; // Rethrow non-MySQL errors
        ^

Error: Can't set headers after they are sent.
    at ServerResponse.OutgoingMessage.setHeader (_http_outgoing.js:346:11)
    at ServerResponse.header (/Users/yourmajesty/Sites/arduino-test/server/node_modules/express/lib/response.js:719:10)
    at ServerResponse.send (/Users/yourmajesty/Sites/arduino-test/server/node_modules/express/lib/response.js:164:12)
    at ServerResponse.json (/Users/yourmajesty/Sites/arduino-test/server/node_modules/express/lib/response.js:250:15)
    at Query.<anonymous> (/Users/yourmajesty/Sites/arduino-test/server/server.js:179:22)
    at Query.<anonymous> (/Users/yourmajesty/Sites/arduino-test/server/server.js:255:50)
    at Query.<anonymous> (/Users/yourmajesty/Sites/arduino-test/server/server.js:276:42)
    at Query._callback (/Users/yourmajesty/Sites/arduino-test/server/server.js:321:46)
    at Query.Sequence.end (/Users/yourmajesty/Sites/arduino-test/server/node_modules/mysql/lib/protocol/sequences/Sequence.js:85:24)
    at Query._handleFinalResultPacket (/Users/yourmajesty/Sites/arduino-test/server/node_modules/mysql/lib/protocol/sequences/Query.js:144:8)

实际上,当URL&#39; / open&#39;用POST方法调用,第一次,一切都好。但第二次,我有这个错误。 我找到的所有答案都谈到了return

整个代码可在此处获取:https://gist.github.com/fcordillot/48428cfccc260635672b9e27d86b5d07

任何人都可以帮助我?

2 个答案:

答案 0 :(得分:1)

以下是您的代码的几个问题:

  1. 您似乎正在修改影响所有用户的status.door.isOpening = true;全局状态。看起来你可能还有这种全球状态的竞争条件。

  2. 您的请求处理程序中有一些路径不会返回任何响应。例如,如果if (status.door.isOpening)为false,则您永远不会发送任何回复。

  3. openTheDoorPlease()中,每次调用时都会添加一个事件处理程序。因此,每次调用它时,另一个事件处理程序就位,您将获得重复的响应处理,并将多次调用您的回调,因此将尝试多次发送响应。这可能是导致“发送后无法设置标题”消息的问题。

  4. 在此功能中,存在问题:

    /*----------  Actions on Arduino  ----------*/
    function openTheDoorPlease(data, callback) {
      // 
      // Do stuff to open the door here 
      //
      //
      socket.emit('event', {
        type: 'open-door'
      });
    
      socket.on('event', function(data) {
        switch (data.type) {
          case 'door-opened':
            if (status.door.isOpening) {
              doorOpened(function(response, log) {
                if (callback !== undefined) callback.call(this, response, log);
              });
            }
            break;
          default:
            break;
        }
      });
    
    }
    

    如果要添加套接字事件处理程序,那么必须在事件发生时将其删除,这样它们就不会堆积起来。但是,这种设计通常不能可靠地工作,因为它受到竞争条件的影响。 Socket.io根本不是请求/响应协议。当您发出事件然后等待响应事件时,您无法知道哪个响应属于哪个请求。如果您有多个用户使用您的系统,他们可以轻松地将哪些事件放在哪里。这段代码需要以不同的方式重做。

    1. 另一个全局变量问题
    2. 在此代码中:

      /*----------  Socket  ----------*/
      var socket;
      io.on('connection', function(sock) {  
        socket = sock;
      
        status.socket.isReady = true;
      });
      

      您正在尝试将连接客户端连接粘贴到全局变量中。这意味着您的服务器只能与一个用户一起可靠地工作。对于连接到服务器的多个用户,它将无法正常工作。您无法在任何服务器环境中以这种方式编码。服务器处理来自许多不同用户的请求,并且它们共享相同的全局环境。您可能需要做的是能够告诉(从给定的http请求)哪个socket.io连接属于该用户,以便您可以获得该连接并向其发送数据。

      1. 同样,您的checkStatus()函数似乎在整个地方使用全局状态。
      2. 除非您打算设计一个仅设计为一次与一个客户端一起工作的客户端/服务器环境,否则需要重新考虑并重做许多此设计以避免使用共享全局状态。如果必须在服务器上保持状态,那么您可能希望该状态的大多数是每用户状态(可能使用会话对象或类似的东西)。任何全局状态必须明确地由所有用户共享,并且如果多个用户同时访问服务器,则必须以不受竞争条件限制的方式访问。

答案 1 :(得分:0)

有两件事,首先不需要使用退货。第二步检查你的函数(setUser,setOpening,openTheDoorPlease等)是否没有发送任何标题或响应。 这是您的代码不使用return。

app.post('/open', checkStatus, function(req, res) {
  if (req.error) {
    console.log(req.log);
    res.json(req.error);
  }

  console.log(currentDate() + colors.gray('>> ') + colors.bold(colors.cyan(req.method)) + ' ' + colors.green('200') + ' ' + req.url);

  var data = req.body;

  status.door.isOpening = true;

  setUser(data, function() {
    setOpening(data, function() {
      openTheDoorPlease(data, function(response, log) {
        if (status.door.isOpening) {
          status.door.isOpening = false;
          console.log(log);
          res.json(response);
        }
      });
    });
  });
});