2016-07-28 32 views
0

我尝试使用Express开发NodeJS应用程序。 这里是我的代码NodeJS,Express,MySQL - 发送后无法设置标题

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“/打开”被调用POST方法,第一次,一切正常。但第二次,我有这个错误。 我找到的所有答案都是关于return的。

整个代码可以在这里找到:https://gist.github.com/fcordillot/48428cfccc260635672b9e27d86b5d07

任何人都可以帮我吗?

+0

'status.door.isOpening = true;'看起来像是在服务器上设置全局数据。这真的是你打算做的 - 更改所有用户看到并使用的所有请求的数据? – jfriend00

+0

你的代码中的这行代码在哪里抛出错误; //反思非MySQL错误'?你告诉我们这就是发源地,但你不会向我们展示与之相关的代码。这就是我们需要看到的。 – jfriend00

+0

另外,您的请求处理程序具有不发送任何响应的代码路径。这也是不正确的。 – jfriend00

回答

1

这里有几个问题与您的代码:

  1. 你似乎改变全局状态与status.door.isOpening = true;影响所有用户。看起来你可能与这个全球化的国家有竞争条件。

  2. 有通过您的请求处理程序不返回任何响应的路径。例如,如果if (status.door.isOpening)是错误的,那么你永远不会发送任何回应。

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

在此功能中,有问题:

/*---------- 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事件处理程序,则必须在事件发生时,使他们不要堆放卸下。但是,这种设计一般不会可靠地工作,因为它受到竞争条件的限制。 Socket.io根本不是一个请求/响应协议。当你发出一个事件然后等待一个响应事件时,你无法知道哪个响应属于哪个请求。如果你有多个用户使用你的系统,他们可以很容易地混淆哪些事件发生在哪里。这段代码需要重做可能是另一种方式。

  • 另一个全局变量的问题
  • 在此代码:

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

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

    1. 类似地,您的checkStatus()函数似乎在全局使用全局状态。

    除非你打算设计一个只设计过一次处理一个客户端可用的客户端/服务器环境中,需要重新思考了不少这样的设计和重做,以避免使用全球共享州。如果你必须在服务器上保持状态,那么你可能希望大部分状态是按用户状态(可能使用会话对象或类似的东西)。任何全局状态都必须明确地打算由所有用户共享,并且如果多个用户同时访问服务器,则必须以不受竞态条件影响的方式进行访问。

    0

    两件事,首先不需要使用return。然后检查你的函数(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); 
         } 
         }); 
        }); 
        }); 
    }); 
    
    +0

    感谢您的回答! 你可以在这里找到整个代码:https://gist.github.com/fcordillot/48428cfccc260635672b9e27d86b5d07 –

    +0

    我没有任何环境来测试,但从第50行到第57(你的中间件编辑标题)的评论,并告诉我如果它有效。 – Martin

    +0

    不,与行注释相同的问题... –

    相关问题