当前位置: 首页 > 工具软件 > WebUploader > 使用案例 >

webuploader 断点续传

宦炜
2023-12-01

webuploader 实现 断点续传

webuploader是百度开发的上传文件前端控件。可支持html5和flash,因此对浏览器的兼容比较好。因为需要用到ie8,ie8不支持html5,
所以必须支持flash上传。

断点续传原理:
1)将大分件分片上传,比如每次传送3m。
2)后台在上传完毕后将分片上传的文件合并为一个文件。

技术要求:
1)前端页面支持分件拆分读取。html5是支持的。IE早期版本不能支持,可以用flash来替代实现。

实现步骤:
1)页面接受用户传入文件。
2)页面用户点击“上传”。
3)页面将文件的基本信息发送到服务端,包括文件名称,大小,修改时间 或者 文件md5(文件md5可加载三方md5算法,但在前端获取需要花费大量时间),
要求不是很高可以选第一种方案
4)服务端接受请求,根据md5生成目录。
5)页面将即将上传的分片信息(不是分片文件)上传到服务端请求验证,判断是否该分片是否已经上传,已经上传则该分片不再重复上传。
6)页面分片传送文件到服务端。
7)服务端将接受到的分片文件放置在md5目录下。
8)页面分片上传完毕,发送合并请求。
9)服务端接受合并请求,将文件合并后放置到指定目录,然后删除临时md5目录。
10)完毕。

实现方法:
js调用webuploader上传文件,配置为分片上传。
这样可以实现分片上传,但是如果要实现断点续传(比如昨天上传了一部分,关闭浏览器后,今天重新上传的情况),
还需要调用webupload提供的hook(WebUploader.Uploader.register)实现上传前,上传中,上传完成后的事件触发,发送到服务端请求。

代码框架概述:
// uploader 初始化
var uploader = new WebUploader.Uploader({
// 选完文件后,是否自动上传。
//auto: false,

        //runtimeOrder: flash,html5,  // 优先使用flash上传

        // swf文件路径
        swf: '/public/lib/webuploader/0.1.5/Uploader.swf',

        //是否要分片处理大文件上传。
        chunked: true,

        // 如果要分片,分多大一片? 默认大小为5M.
        chunkSize: chunkSize,

        // 如果某个分片由于网络问题出错,允许自动重传多少次?
        chunkRetry: 3,

        // 上传并发数。允许同时最大上传进程数[默认值:3]
        threads: 1,

        // 去重
        duplicate: true,

        // 文件接收服务端。
        server: server_url,

        // 选择文件的按钮。可选。
        // 内部根据当前运行是创建,可能是input元素,也可能是flash.
        pick: {
            id: filePicker,
            multiple: false
        },

        // 不压缩image, 默认如果是jpeg,文件上传前会压缩一把再上传!
        resize: false,

        // 上传本分片时预处理下一分片
        prepareNextFile: true,

        //formData: function(){return {uniqueFileName: '333'};}
        formData: {uniqueFileName: uniqueFileName}
    });
    // 文件上传过程中创建进度条实时显示。
    uploader.on('uploadProgress', function (file, percentage) {
        // 具体逻辑...
    });

    // 文件上传成功处理。
    uploader.on('uploadSuccess', function (file, response) {
        // 具体逻辑...
    });
    // 文件上传失败处理。
    uploader.on('uploadError', function (file) {
        // 具体逻辑...
    });
    // 长传完毕,不管成功失败都会调用该事件,主要用于关闭进度条
    uploader.on('uploadComplete', function (file) {
        // 具体逻辑...
    });

/** 实现webupload hook,触发上传前,中,后的调用关键 **/
WebUploader.Uploader.register({
“before-send-file”: “beforeSendFile”, // 整个文件上传前
“before-send”: “beforeSend”, // 每个分片上传前
“after-send-file”: “afterSendFile” // 分片上传完毕
}, {
beforeSendFile: function (file) {
var task = new $.Deferred();
var start = new Date().getTime();

    //拿到上传文件的唯一名称,用于断点续传
    uniqueFileName = md5(file.name + file.size);
    
    $.ajax({
        type: "POST",
        url: check_url,   // 后台url地址
        data: {
            type: "init",
            uniqueFileName: uniqueFileName,
        },
        cache: false,
        async: false,  // 同步
        timeout: 1000, //todo 超时的话,只能认为该文件不曾上传过
        dataType: "json"
    }).then(function (data, textStatus, jqXHR) {            
        if (data.complete) { //若存在,这返回失败给WebUploader,表明该文件不需要上传                
            task.reject();
            // 业务逻辑...

        } else {
            task.resolve();
        }
    }, function (jqXHR, textStatus, errorThrown) { //任何形式的验证失败,都触发重新上传
        task.resolve();
    });

    return $.when(task);
}
, beforeSend: function (block) {
    //分片验证是否已传过,用于断点续传
    var task = new $.Deferred();
    $.ajax({
        type: "POST",
        url: check_url,
        data: {
            type: "block",
            chunk: block.chunk,
            size: block.end - block.start
        },
        cache: false,
        async: false,  // 同步
        timeout: 1000, //todo 超时的话,只能认为该分片未上传过
        dataType: "json"
    }).then(function (data, textStatus, jqXHR) {
        if (data.is_exists) { //若存在,返回失败给WebUploader,表明该分块不需要上传
            task.reject();
        } else {
            task.resolve();
        }
    }, function (jqXHR, textStatus, errorThrown) { //任何形式的验证失败,都触发重新上传
        task.resolve();
    });
    return $.when(task);
}
, afterSendFile: function (file) {        
    var chunksTotal = Math.ceil(file.size / chunkSize);
    if (chunksTotal > 1) {
        //合并请求
        var task = new $.Deferred();
        $.ajax({
            type: "POST",
            url: check_url,
            data: {
                type: "merge",
                name: file.name,
                chunks: chunksTotal,
                size: file.size
            },
            cache: false,
            async: false,  // 同步
            dataType: "json"
        }).then(function (data, textStatus, jqXHR) {
            // 业务逻辑...
            
        }, function (jqXHR, textStatus, errorThrown) {
            current_uploader.uploader.trigger('uploadError');
            task.reject();
        });
        return $.when(task);
    }
}

});

温馨提示:

  1. 前端用html5和flash上传时上传的文件修改事件的时区(美国时间和中国事件)可能不一样,自己需要在后台判断处理,不然可能出现错误。
  2. 如果同一个页面有多个webuploader上传,自己根据业务情况特殊处理,因为WebUploader.Uploader.register是全局的,对每个上传都有影响。
 类似资料: