zoukankan      html  css  js  c++  java
  • webuploader 断点续传

    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是全局的,对每个上传都有影响。



  • 相关阅读:
    bootstrap
    史上最全Html和CSS布局技巧
    三种实现左右固定,中间自适应的三栏布局方式
    网页布局常用样式属性
    去除inline-block间隙的几种方法
    HTML&CSS——使用DIV和CSS完成网站首页重构
    I want to be a Great Web Front-end Developer
    js常用函数汇总(不定期更新)
    关于git stash的应用总结
    vue 自定义指令
  • 原文地址:https://www.cnblogs.com/mywebnumber/p/5953398.html
Copyright © 2011-2022 走看看