NodeJS,Express,MySQL - 发送后无法设置标题
我尝试使用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
任何人都可以帮我吗?
这里有几个问题与您的代码:
你似乎改变全局状态与
status.door.isOpening = true;
影响所有用户。看起来你可能与这个全球化的国家有竞争条件。有通过您的请求处理程序不返回任何响应的路径。例如,如果
if (status.door.isOpening)
是错误的,那么你永远不会发送任何回应。在
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根本不是一个请求/响应协议。当你发出一个事件然后等待一个响应事件时,你无法知道哪个响应属于哪个请求。如果你有多个用户使用你的系统,他们可以很容易地混淆哪些事件发生在哪里。这段代码需要重做可能是另一种方式。
- 另一个全局变量的问题
- 类似地,您的
checkStatus()
函数似乎在全局使用全局状态。
在此代码:
/*---------- Socket ----------*/
var socket;
io.on('connection', function(sock) {
socket = sock;
status.socket.isReady = true;
});
您正在尝试坚持一个连接的客户端连接到一个全局变量。这意味着您的服务器将只能与一位用户可靠地工作。连接到服务器的多个用户无法正常工作。您无法在任何服务器环境中以此方式编码。服务器处理来自许多不同用户的请求,他们都共享相同的全球环境。你可能需要做的是能够告诉(从一个给定的http请求)哪个连接属于该用户,以便你可以获得该连接并向其发送数据。
除非你打算设计一个只设计过一次处理一个客户端可用的客户端/服务器环境中,需要重新思考了不少这样的设计和重做,以避免使用全球共享州。如果你必须在服务器上保持状态,那么你可能希望大部分状态是按用户状态(可能使用会话对象或类似的东西)。任何全局状态都必须明确地打算由所有用户共享,并且如果多个用户同时访问服务器,则必须以不受竞态条件影响的方式进行访问。
两件事,首先不需要使用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);
}
});
});
});
});
感谢您的回答! 你可以在这里找到整个代码:https://gist.github.com/fcordillot/48428cfccc260635672b9e27d86b5d07 –
我没有任何环境来测试,但从第50行到第57(你的中间件编辑标题)的评论,并告诉我如果它有效。 – Martin
不,与行注释相同的问题... –
'status.door.isOpening = true;'看起来像是在服务器上设置全局数据。这真的是你打算做的 - 更改所有用户看到并使用的所有请求的数据? – jfriend00
你的代码中的这行代码在哪里抛出错误; //反思非MySQL错误'?你告诉我们这就是发源地,但你不会向我们展示与之相关的代码。这就是我们需要看到的。 – jfriend00
另外,您的请求处理程序具有不发送任何响应的代码路径。这也是不正确的。 – jfriend00