在开发过程中遇到需要上传大文件的需求,但是大文件整个上传会导致服务器内存爆炸。
分片上传的思路
利用blob.slice()
方法,根据指定的分片大小对文件进行切割,然后对切割得到的分片分开上传,上传可以指定并发数。服务器接受到所有分片之后,在把所有分片按照正确的顺序合并成完整的文件。
实现
由于实现过程中,后端开发懒得去判断分片是否全部上传完毕,需要前端在分片全部上传完之后在发送一个请求通知后台合并分片。并且webupload对image 类型的文件不分片。最后封装webuploader实现如下:
function upload(file, options) {
// default options
options = $.extend({
folder: '',
success: $.noop,
error: $.noop,
progress: $.noop
}, options);
var errorHandler = options.error;
var successHandler = options.success;
var progressHanlder = options.progress;
var fileMd5 = uuidv4();
var runtimeForRuid = new WebUploader.Runtime.Runtime();
var wuFile = new WebUploader.File(new WebUploader.Lib.File(WebUploader.guid('rt_'), file));
var chunkSize = 1 * 1024 * 1024;
var chunked = file.size > chunkSize;
//
var events = $.extend({
uploadBeforeSend: function(_, data) {
if (chunked) {
data.uuid = fileMd5;
}
},
uploadProgress: progressHanlder
}, file.type.indexOf('image') >= 0 || !chunked ? {
uploadSuccess: function(_, data) {
successHandler(data);
},
uploadError: function() {
errorHandler('上传失败');
}
} : {
uploadFinished: function() {
var file = uploader.getFiles()[0];
if (!file || file.type.indexOf('image') >= 0) {
return;
}
$.post('/public/stream-file/', {
csrf_token: bms.csrf_token,
chunk: -1,
uuid: fileMd5,
upload_folder: options.folder,
name: file.name
}, null, 'json').done(successHandler).fail(function() {
errorHandler('上传失败');
});
}
});
var uploader = WebUploader.create({
fileNumLimit: 1,
chunked: chunked,
chunkSize: chunkSize,
prepareNextFile: true,
server: '/public/stream-file/',
fileVal: 'attachement',
formData: {
csrf_token: bms.token,
upload_folder: options.folder
}
});
$.each(events, function(name, handler) {
uploader.on(name, handler);
});
// 开始上传
uploader.addFiles(wuFile);
uploader.upload();
return uploader;
}