Не удается отправить заголовки после их отправки. Загрузка файла, проблема с асинхронностью?

Я разрабатываю функцию загрузки нескольких файлов с использованием ajax, nodejs, express и модуля огромного размера.

Однако иногда я получаю сообщение об ошибке Can't set headers after they are sent. из трассировки стека ошибок из-за строки return res.send({ status: 'success', files: files['upload']

Я попытался проверить, что могло заставить его отправлять более одного раза, и я включил счетчик, чтобы убедиться, что он сработает один раз после загрузки всех файлов, но иногда ошибка все равно возникает.

var express     = require('express'),
    router      = express.Router(),
    formidable  = require('formidable'),
    util        = require('util'),
    fs          = require('fs'),
    form        = new formidable.IncomingForm(),
    path        = require('path'),
    nodeHomeDir = path.dirname(require.main.filename);

form.type = 'multipart';
form.multiples = true;
form.maxFieldsSize = 52428800;
form.uploadDir = nodeHomeDir + '/tmp';
form.keepExtensions = true;

/* POST to /files to upload or delete files */
router.post('/', function (req, res, next) {

  form.parse(req, function (err, fields, files) {
    if (!files['upload'][0]) return res.send({ status: 'fail', message: 'No files provided.' });

    req.on('aborted', function () {
      return res.send({ message: 'fail' });
    });

    var webinarID     = fields.webinarID,
        uploadDirName = nodeHomeDir + '/webinarFiles/' + webinarID,
        filesLength   = Object.keys(files['upload']).length,
        counter       = 0;

    if (!webinarID) return res.send({ status: 'fail', message: 'No webinar ID provided.' });

    if (!fs.existsSync(uploadDirName)) {
      fs.mkdirSync(uploadDirName);
    }

    for (file in files['upload']) {
      if (files['upload'][file] && files['upload'][file].path && files['upload'][file].name) {
        var stream = fs.createReadStream(files['upload'][file].path).pipe(fs.createWriteStream(uploadDirName + '/' + files['upload'][file].name));
        stream.on('finish', function () {
          counter++;
          if (counter === filesLength) {
            // deleteFilesFromFolder(nodeHomeDir + '/tmp');
            return res.send({ status: 'success', files: files['upload'] });
          }
        });
      }
    }

  });

});

person jSmith    schedule 08.10.2015    source источник
comment
Что ж, массив ключей, который вы получаете от Object.keys(), не обязательно имеет ту же длину, что и количество свойств, через которые будет проходить цикл for ... in. Если вы хотите быть уверенным, что выполняете итерацию только по одним и тем же ключам, то итерация по результату Object.keys() выполняется непосредственно с помощью простого цикла for или с помощью .forEach().   -  person Pointy    schedule 08.10.2015


Ответы (1)


Попробуйте для этого:

    var async = require('async');
    async.eachSeries(files['upload'], function(elem,asynccallback){
     if (files['upload'][file] && files['upload'][file].path && files['upload'][file].name) {
            var stream = fs.createReadStream(files['upload'][file].path).pipe(fs.createWriteStream(uploadDirName + '/' + files['upload'][file].name));
            stream.on('finish', function () {
              counter++;
              if (counter === filesLength) {
                // deleteFilesFromFolder(nodeHomeDir + '/tmp');
                return res.send({ status: 'success', files: files['upload'] });
              }
            });
          }
    asynccallback();
});
person Subburaj    schedule 08.10.2015