我有一个基于Node.JS的服务器。服务器的一个功能是从移动客户端接收照片并将其存储在mongodb中。当连接错误时,文件上载过程失败,客户端收到错误并重试,一切都按预期工作,但有时,在上载失败后,服务器崩溃时出现“无法在发送后设置标头” “错误。下面是服务器生成的错误:用户通过身份验证,然后上传过程失败,PUT /v1/add_photo.json命令返回错误代码400,但似乎仍然调用了add_photo.json的剩余功能 - 为什么?因此,会生成此错误,因为在最后,send_failure函数将再次设置标头。 (当“成功”上传失败时 - 在add_photo.json返回错误代码400之后,不会调用其他函数,并且一切都按预期工作)
3/23/2014 16:6:41 0.0.2 handlers/users.js: authenticate_user:
Error: Request aborted
at IncomingMessage <anonymous
(/floomit/node/node/node_modules/express/node_modules/connect/node_modules/multiparty/index.js:93:17)
at IncomingMessage.EventEmitter.emit (events.js:92:17)
at abortIncoming (http.js:1911:11)
at Socket.socket.onend (http.js:2010:7)
at Socket.g (events.js:175:14)
at Socket.EventEmitter.emit (events.js:117:20)
at _stream_readable.js:920:16
at process._tickCallback (node.js:415:13)
PUT /v1/add_photo.json 400 9542ms - 467b
3/23/2014 16:6:41 0.0.2 handlers/streams.js: add_photo:
3/23/2014 16:6:41 0.0.2 data/streams.js: store_file:
3/23/2014 16:6:41 0.0.2 data/streams: store_file: err:
{ [Error: ENOENT, open '/tmp/4684-1425605.jpg'] errno: 34, code: 'ENOENT', path:'/tmp/4684-1425605.jpg' }
3/23/2014 16:6:41 0.0.2 handlers/streams.js: add_photo: err
{ [Error: ENOENT, open '/tmp/4684-1425605.jpg'] errno: 34, code: 'ENOENT', path:'/tmp/4684-1425605.jpg' }
http.js:733
throw new Error('Can\'t render headers after they are sent to the client.'
^
Error: Can't render headers after they are sent to the client.
at ServerResponse.OutgoingMessage._renderHeaders (http.js:733:11)
at ServerResponse.res._renderHeaders
(/floomit/node/node/node_modules/express/node_modules/connect/lib/patch.js:69:27)
at ServerResponse.writeHead (http.js:1150:20)
at ServerResponse.res.writeHead
(/floomit/node/node/node_modules/express/node_modules/connect/lib/patch.js:75:22)
at Object.exports.send_failure (/floomit/node/node/handlers/helpers.js:78:9)
at /floomit/node/node/handlers/streams.js:377:21
at /floomit/node/node/node_modules/async/lib/async.js:428:21
at /floomit/node/node/data/streams.js:495:13
at /floomit/node/node/node_modules/mongodb/lib/mongodb/gridfs/gridstore.js:294:22
at Object.oncomplete (fs.js:107:15)
从上面的日志行中可以看出(前面有日期的行由我的服务器打印),输入函数add_photo,它调用函数store_file,该函数失败。似乎失败的原因是文件未成功上传到服务器,如ENOENT错误所示。这应该只是导致错误代码返回到客户端并且客户端重新传输,而是服务器崩溃。这不会一直发生,大多数情况下客户端返回错误代码并重新发送。我事件尝试修改store_file()函数以始终返回上面生成的ENOENT错误并且不发生崩溃,客户端只是重新发送。
以下是服务器的相关代码:
// stream handler
exports.add_photo = function (req, res) {
var new_photo = new Photo();
async.waterfall([
// store image file
function (cb) {
stream_data.store_file(req.files.file_image.path, cb);
},
function (imageFileId, cb) {
new_photo.imageFileId = imageFileId;
stream_data.add_photo(new_photo, cb);
}
],
function (err, final_photo) {
if (err) {
helpers.floomit_log("handlers/streams.js: add_photo: err");
helpers.floomit_log(err);
helpers.send_failure(res, err);
} else {
helpers.send_success(res, final_photo.response_obj());
}
});
};
// stream_data
exports.store_file = function (file_full_path, callback) {
async.waterfall([
function (cb) {
fileId = db.ObjectID();
fileGS = new db.GridStore(db.db, fileId, "w", {"chunk_size":1024*4});
fileGS.writeFile(file_full_path, cb);
}
],
function (err, results) {
if (err) {
helpers.floomit_log("data/streams: store_file: err:");
helpers.floomit_log(err);
callback(err);
} else {
callback(null, fileId);
}
});
};
// stream_data
exports.add_photo = function (new_photo, callback) {
var query = {};
query["$or"] = [];
async.waterfall([
function (cb) {
new_photo._id = db.ObjectID();
db.photos.insert(new_photo, {w:1}, cb);
},
function (result, cb) {
for (i = 0; i < new_photo.streams.length; i++) {
query["$or"].push({"user":new_photo.streams[i].user,"name":new_photo.streams[i].name});
}
db.streams.update(
query,
{"$inc" : {"photoCount":1}, "$set" : {"timestampU":new_photo.timestamp}},
{w:1, multi:true},
cb);
}
],
function (err) {
if (err) {
helpers.floomit_log("data/streams.js: add_photo: err:");
helpers.floomit_log(err);
callback(err);
} else {
callback(null, new_photo);
}
});
};
// helpers
exports.send_success = function(res, data) {
res.writeHead(200, {"Content-Type": "application/json"});
var output = { error: "none", data: data };
res.end(JSON.stringify(output) + "\n");
};
// helpers
exports.send_failure = function(res, err) {
var code = (err.code) ? err.code : err.name;
res.writeHead(code, { "Content-Type" : "application/json" });
res.end(JSON.stringify({ error: code, message: err.message }) + "\n");
}
当发生这种情况时,send_failure函数不会返回正确的HTTP错误,我需要解决这个问题,但这不是问题所在。 (只是想指出来这个问题没有提到这里)
谢谢你, 加里