javascript - 如果大于 5MB,Flow.js(在 Angular.js 中)上传到 node.js 将失败

标签 javascript node.js angularjs file-upload xmlhttprequest

所以我默认上传 1Mb block ,并且一次同时上传 5 个 block ,但是在这些 block 完成后,我的客户端不会发送剩余的 block 。因此最大输出为 5Mb,有人知道为什么吗?我没有更改任何其他默认设置,testChunks 已启用。

我的 Node 侧帖子是根据 smartsprocket 的答案建模的:

reassemble binary after flow.js upload on node/express server

我的获取方基于:

//'found', filename, original_filename, identifier
//'not_found', null, null, null
$.get = function(req, callback) {
    var chunkNumber = req.param('flowChunkNumber', 0);
    var chunkSize = req.param('flowChunkSize', 0);
    var totalSize = req.param('flowTotalSize', 0);
    var identifier = req.param('flowIdentifier', "");
    var filename = req.param('flowFilename', "");

    if (validateRequest(chunkNumber, chunkSize, totalSize, identifier, filename) == 'valid') {
        var chunkFilename = getChunkFilename(chunkNumber, identifier);
        fs.exists(chunkFilename, function(exists) {
            if (exists) {
                callback('found', chunkFilename, filename, identifier);
            } else {
                callback('not_found', null, null, null);
            }
        });
    } else {
        callback('not_found', null, null, null);
    }
};

我不明白为什么它没有再次触发,流程如下:尝试获取文件 block ,无 block ,回复 404,POST CHUNK,POST PARTLY_DONE。 (每次同时上传 x5)。 然后它不再上传 block ,它只是在某些部分停止(许多console.logs还没有解决这个问题)。

我已经从永久性错误中删除了 404,这样应用程序就不会停止,但它仍然会停止。

任何帮助都会很棒,因为文件有时可能大于 5Mb。

谢谢, 乔

编辑(完整邮政编码):

客户端设置(仅更改 mg-flow 的默认设置):

chunkSize: 1024 * 1024,
forceChunkSize: false,
simultaneousUploads: 5,
singleFile: false,
fileParameterName: 'file',
progressCallbacksInterval: 0, //instant feedback
speedSmoothingFactor: 1,
query: {},
headers: {},
withCredentials: false,
preprocess: null,
method: 'multipart',
prioritizeFirstAndLastChunk: false,
target: '/',
testChunks: true,
generateUniqueIdentifier: null,
maxChunkRetries: undefined,
chunkRetryInterval: undefined,
permanentErrors: [415, 500, 501],
onDropStopPropagation: false

通过将 target 选项设置为 url,在标签中动态设置目标,这是范围内动态创建的变量,因此它会上传到 tmp,然后在所有 block 接收到讲座目录后移动,以使组织和管理更容易,例如删除

i.e. uploadFile/{{module.id}}/{{lecture.id}}

然后是服务器端,

var multipart = require('connect-multiparty');
var multipartMiddleware = multipart();

获取

 //Handle status checks on chunks through Flow.js
 app.get('/uploadFile/:mId/:id', lectureRoutes.fileGet);

 exports.fileGet = function(req, res) {
   flow.get(req, function(status, filename, original_filename, identifier) {
      console.log('GET', status);
      res.send(200, (status == 'found' ? 200 : 404));
   });
 }


 //'found', filename, original_filename, identifier
//'not_found', null, null, null
$.get = function(req, callback) {
    var chunkNumber = req.param('flowChunkNumber', 0);
    var chunkSize = req.param('flowChunkSize', 0);
    var totalSize = req.param('flowTotalSize', 0);
    var identifier = req.param('flowIdentifier', "");
    var filename = req.param('flowFilename', "");

    if (validateRequest(chunkNumber, chunkSize, totalSize, identifier, filename) == 'valid') {
        var chunkFilename = getChunkFilename(chunkNumber, identifier);
        fs.exists(chunkFilename, function(exists) {
            if (exists) {
                callback('found', chunkFilename, filename, identifier);
            } else {
                callback('not_found', null, null, null);
            }
        });
    } else {
        callback('not_found', null, null, null);
    }
 };

发布

//To Save File
app.post('/uploadFile/:mId/:id', multipartMiddleware, lectureRoutes.fileAddPost);

//FIX THIS
exports.fileAddPost = function(req,res){
   flow.post(req, function(status, filename, original_filename, identifier, currentTestChunk,     numberOfChunks) {
     console.log('POST', status, original_filename, identifier);
     if (status === 'done' && currentTestChunk > numberOfChunks) {
        var stream = fs.createWriteStream('./tmp/' + filename);
        //EDIT: I removed options {end: true} because it isn't needed
        //and added {onDone: flow.clean} to remove the chunks after writing
        //the file.
        flow.write(identifier, stream, {onDone: flow.clean}); 
        //Once written move the file.
        mv('./tmp/'+filename,'./public/files/'+req.params.mId+'/'+req.params.id+'/'+filename,  {mkdirp: true,clobber: false}, function(err){
            if(err == 'EEXIST') {
                //FILE ALREADY EXIST STOP IT FROM BEING RE-ADDED TO DB, although allow file to be moved incase its newer
            }
            else if(!err){
                var set = {};
                Modules.findById(req.params.mId, function(err,module){
                    module.Lectures.id(req.params.id).Files.push({"fileName" : filename});
                    module.save(function(err){
                        if(err) console.log(err)
                        //return id of file back
                        else{
                            var link = module.Lectures.id(req.params.id).Files;
                            res.send(200, link[link.length-1]._id)
                        }
                    })
                })
            }
        });
    }

  });
}


 //'partly_done', filename, original_filename, identifier
//'done', filename, original_filename, identifier
//'invalid_flow_request', null, null, null
//'non_flow_request', null, null, null
$.post = function(req, callback){

       var fields = req.body;
       var files = req.files;
       var chunkNumber = fields['flowChunkNumber'];
       var chunkSize = fields['flowChunkSize'];
       var totalSize = fields['flowTotalSize'];
       var identifier = cleanIdentifier(fields['flowIdentifier']);
       var filename = fields['flowFilename'];

       var original_filename = fields['flowIdentifier'];

       if (!files[$.fileParameterName] || !files[$.fileParameterName].size) {
           callback('invalid_flow_request', null, null, null);
           return;
       }
       var validation = validateRequest(chunkNumber, chunkSize, totalSize, identifier, filename, files[$.fileParameterName].size);
       if (validation == 'valid') {
           var chunkFilename = getChunkFilename(chunkNumber, identifier);


      fs.rename(files[$.fileParameterName].path, chunkFilename, function(){

        // Do we have all the chunks?
        var currentTestChunk = 1;
        var numberOfChunks = Math.max(Math.floor(totalSize/(chunkSize*1.0)), 1);
        var testChunkExists = function(){
              fs.exists(getChunkFilename(currentTestChunk, identifier), function(exists){
               currentTestChunk++;
               if(exists){
                  if(currentTestChunk>numberOfChunks) {
                      callback('done', filename, original_filename, identifier, currentTestChunk, numberOfChunks);
                  } else {
                    // Recursion
                    testChunkExists();

                  }
                } else {

                  //Add currentTestChunk and numberOfChunks to the callback

                  callback('partly_done', filename, original_filename, identifier, currentTestChunk, numberOfChunks);
                }
              });
            }
        testChunkExists();
      });
    } else {
          callback(validation, filename, original_filename, identifier);
    }
}

最佳答案

您在 flow.write 之后调用 mv() 但应在 flow.write 的回调中调用它。 mv() 在 flow.write 完成之前被调用,并且因为您的 res.send 在此函数中,所以它没有完成。

尝试将 res.send 移动到 flow.post 调用的顶部,看看是否获得了所有 block 。

exports.fileAddPost = function(req,res){
   flow.post(req, function(status, filename, original_filename, identifier,         currentTestChunk,     numberOfChunks) {
 console.log('POST', status, original_filename, identifier);
 res.send(200);
 ...
}

如果有效,则可能是因为 mv() 不在回调中。将其移至回调中,但暂时将 res.send 保留在原处。

exports.fileAddPost = function(req,res){
   flow.post(req, function(status, filename, original_filename, identifier, currentTestChunk,     numberOfChunks) {

     ...

     flow.write(identifier, stream, { onDone: flow.clean }, function(err) {
            if (err) {
                console.log(err);
            }
            else {
                //call mv() here
            }
       });

然后在 flow.write ($.write) 中为其签名添加回调。

$.write = function(identifier, writableStream, options, callback) {

    ...

    //At the bottom of this function, after calling options.onDone(identifier)
    if (options.onDone) {
        options.onDone(identifier);
    {
    return callback(null);

您还应该添加错误处理。在 if (exists) { ... } 之后,您可以添加一个 else if((!exists) && number === 1) { return callback('Cannot write file from chunks, chunks don\t exit.'); 然后在这之后将是 else block 。

现在尝试一下,看看是否一切正常。如果有效,请尝试将 res.send 移回到您的 mv() 函数中。如果它不起作用,那么这个函数可能不是异步的。

关于javascript - 如果大于 5MB,Flow.js(在 Angular.js 中)上传到 node.js 将失败,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25274339/

相关文章:

javascript - $digest 已经运行 - AngularJS

javascript - 在任何网站上监听 Oculus Controller 事件

javascript - 将canvas转换为html5中带有背景图像的图像

javascript - Bootstrap 4 pills 点击内容显示在下方和/或不显示

Node.js Selenium 找不到元素。没有这样的元素错误

javascript - 在 Angularjs Controller 中用作计数器的静态 javascript 变量

javascript - Directionsservice 路线航点文字

node.js - 连续迭代 mongodb 游标(在移动到下一个文档之前等待回调)

node.js - 发送后表达响应正文

javascript - Highcharts箱线图图表定制