Node.JS崩溃时“发送后无法设置标头”错误

时间:2014-04-18 14:45:55

标签: javascript json node.js mongodb

我有一个基于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错误,我需要解决这个问题,但这不是问题所在。 (只是想指出来这个问题没有提到这里)

谢谢你, 加里

0 个答案:

没有答案