【问题标题】:Filereader and Socket.io uploader: subsequent uploads include previous uploadsFilereader 和 Socket.io 上传器:后续上传包括之前的上传
【发布时间】:2013-12-15 23:42:36
【问题描述】:

我正在尝试在 html5/js 和节点中实现一个文件上传器,它以块的形式上传大文件。它非常适合单次上传。但是当我尝试在同一页面上再次上传时,它会进入一个无限循环,看起来它正在尝试一次重新上传上一次上传和新文件。

客户端.js

$('input').change(function() {
  var file = this.files[0]
  var fileSize = file.size
  var fileName = file.name
  // file size gate:
  var fileSizeLimit = 15000000 // ~15mb
  if (fileSize <= fileSizeLimit) {
    // get preview blob
    var windowURL = window.URL || window.webkitURL
    var blobURL = windowURL.createObjectURL(this.files[0])
    // render preview image
    // render status progress
    // set progress to 0

    // read the file to server:
    var reader = new FileReader()
    console.log('new filereader init')
    socket.emit('startSend', fileName, fileSize, entryID)
    console.log('startSend emitted now for ' + fileName) 

    reader.onload = function(event) {
      var data = event.target.result
      console.log('reader onload for ' + fileName)
      socket.emit('sendPiece', data, fileName, fileSize, entryID)
    }

    socket.on('morePlease', function (place, entryID, percent){
      progressUpdate(percent)
      var chunkSize = 262144
      var startPlace = place * chunkSize // The newBlock's Starting Position
      var newBlock = file.slice(startPlace, startPlace + Math.min(chunkSize, (fileSize-startPlace)))
      reader.readAsBinaryString(newBlock) // triggers reader onload
    })

    function progressUpdate(percent){
      console.log('current percent is: ' + percent + '%')
      $('.sendfile .progress').val(percent).text(percent + '%')
    }

    socket.on('sendSuccessful', function(entryID){
      console.log('sendSuccessful triggered for ' + entryID + '. File should be in temp folder.')
      $('.status .sendfile').addClass('hidden')
      $('.status .savetext').removeClass('hidden')
      $('.status .saved').removeClass('hidden')
      $('.sendfile .progress').val(0).text('0%')
    })

  } else { 
    // file size is too big
  }

}) // close input onchange event

服务器.js

  // start file upload
  var chunkSize = 262144

  socket.on('startSend', function(fileName, fileSize, entryID) {
    var files = {}
    console.log('startSend hit for ' + fileName)
    files[fileName] = { // create new entry in files {}
      fileSize : fileSize,
      data : '',
      downloaded : 0
    }
    var fileWriting = files[fileName]
    var tempPath = 'temp/' +  entryID + '-' + fileName
    var place = 0 // stores where in the file we are up to
    console.log('place: in startSend, the place for ' + fileName + ' is ' + place) //

    try{
      var stat = fs.statSync(tempPath)
      if(stat.isFile())
      {
        fileWriting['downloaded'] = stat.size
        place = stat.size / chunkSize; // we're passing data in 1/4 mb increments
        console.log('downloaded: ' + stat.size)
      }
    }
    catch(er){} // it's a new file
    fs.open(tempPath, "a", 0755, function(err, fd){
      if(err)
      {
        console.log(err)
      }
      else // requesting
      {
        fileWriting['handler'] = fd //We store the file handler so we can write to it later
        var percent = 0
        socket.emit('morePlease', place, entryID, percent) // requesting more file pieces
      }
    })

    // processing the file pieces from client
    socket.on('sendPiece', function(data, fileName, fileSize, entryID) {
      console.log('sendPiece hit for ' + entryID + ' ' + fileName) 
      fileWriting['downloaded'] += data.length
      fileWriting['data'] += data
      if(fileWriting['downloaded'] == fileWriting['fileSize']) { // If File is Fully Uploaded
        fs.write(fileWriting['handler'], fileWriting['data'], null, 'Binary', function(err, Writen){
          console.log('file ' + entryID + 'has been written to temp folder: ' + fileName)
          socket.emit('sendSuccessful', entryID)
        })
      }
      else if(fileWriting['data'].length > 10485760){ //If the Data Buffer reaches 10MB
        fs.write(fileWriting['handler'], fileWriting['data'], null, 'Binary', function(err, Writen){
          fileWriting['data'] = ""; //Reset The Buffer
          var place = fileWriting['downloaded'] / chunkSize
          var percent = (fileWriting['downloaded'] / fileWriting['fileSize']) * 100
          socket.emit('MorePlease', place, entryID, percent) // requesting more file pieces
        })
      }
      else { // need more file pieces
        var place = fileWriting['downloaded'] / chunkSize
        console.log('MorePlease: ' + fileName + ' pieces needed at place ' + place + ' and percent ' + percent)
        var percent = (fileWriting['downloaded'] / fileWriting['fileSize']) * 100
          socket.emit('morePlease', place, entryID, percent) // requesting more file pieces
      }
    })
  }) // close startSend

服务器日志:这是基于console.logs的节点日志分散在各处:

上传第一个文件没问题:

startSend hit for file1.jpeg
place: in startSend, the place for file1.jpeg is 0
sendPiece hit for 52a530f8649b5db8b2000001 file1.jpeg
file 52a530f8649b5db8b2000001has been written to temp folder: file1.jpeg

对于后续文件:

startSend hit for file2.JPG
place: in startSend, the place for file2.JPG is 0
sendPiece hit for 52a530f8649b5db8b2000001 file1.jpeg
MorePlease: file1.jpeg pieces needed at place 1.9332275390625 and percent undefined
sendPiece hit for 52a530f8649b5db8b2000001 file1.jpeg
MorePlease: file1.jpeg pieces needed at place 0.96661376953125 and percent undefined
sendPiece hit for 52a530f8649b5db8b2000001 file2.JPG
MorePlease: file2.JPG pieces needed at place 2.6120567321777344 and percent undefined

...无限循环。


webinspector 消息:

reader onload for file1.jpeg (client.js, line 260)
reader onload for file2.JPG (client.js, line 260)
current percent is: 270.227552566774% (client.js, line 273, x2)
current percent is: 242.3942545981759% (client.js, line 273)
InvalidStateError: DOM Exception 11: An attempt was made to use an object that is not, or is no longer, usable.

...无限循环


我已经为此绞尽脑汁好几个小时了,试图自己单步调试代码。我不是专业的开发人员,因此非常感谢任何帮助!

【问题讨论】:

    标签: javascript jquery html node.js filereader


    【解决方案1】:

    我从不使用 Socket 来通过 Node.js 上传文件。基本上,http 做得很好。这是示例代码:

    var http = require('http'),
        fs = require('fs');
    
    var server = http.createServer();
    server.listen(8080);
    console.log('Start is started on port 8080');
    
    server.on('request', function(req, res) {
        var file = fs.createWriteStream('sample.jpg');
        var fileSize = req.headers['content-length'];
        var uploadedSize = 0;
    
        req.on('data', function (chunk) {
            uploadedSize += chunk.length;
            var buffer = file.write(chunk);
            if(buffer == false)
                req.pause();
        });
    
        file.on('drain', function() {
            req.resume();
        });
    
        req.on('end', function() {
            res.write('File uploading is completed!!');
            res.end();
        });
    });
    

    如果要通知客户端上传进度,可以在data事件中添加一些逻辑。

    顺便说一句,我发现有人已经问过同样的问题并得到了答案。答案发布了指向教程的链接。我已经检查并认为这是您正在寻找的解决方案。检查这个Node.js file upload capabilities: Large Video Files Uploading with support for interruption

    【讨论】:

    • 之所以选择socket,是因为我不想在客户端提交表单时刷新页面。节点 server.on 请求类型模型不是只适用于新的 html 页面请求吗?
    • 我发布的示例是针对服务器端的。即使您使用 Socket 或 http 进行连接,您仍然需要在客户端有一个页面(或本机应用程序)来向服务器提交文件。如果你想让你的客户端得到通知,它必须实现事件(例如“sendSuccessful”事件)来接收和处理来自服务器的信息。
    • 在客户端的情况下,通过输入 onchange 事件或类似的东西,我如何将事件传递给服务器而不必在客户端触发页面刷新(对于 http 服务器注册“请求”)?也许这个客户端的一个例子会让我更清楚。再次感谢。
    • re:指向 nettuts 的链接:这实际上是我的代码大致基于 off 的内容。但我也会仔细检查一下。如果我可以使用您的 http 方法通过页面重新加载进行上传,我真的更愿意这样做。
    • 是的,最终切换到 http + node busboy 解决方案。 Socket.io 很棒,但不值得为文件而痛苦。谢谢!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-04-22
    • 2016-08-11
    • 2015-04-22
    • 1970-01-01
    相关资源
    最近更新 更多