我正在尝试在html5 / js中实现一个文件上传器,以及以块的形式上传大文件的节点。它适用于单个上传。但是当我尝试再次在同一页面上传时,它会进入无限循环,看起来它正在尝试重新上载上一次上传和新文件。
Client.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
Server.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.
......无限循环
我已经花了好几个小时在脑子里绞尽脑汁,试图自己逐步完成代码。我不是贸易开发商,所以任何帮助都会受到超级赞赏!
答案 0 :(得分:0)
我从未使用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!