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是全局的,對每個上傳都有影響。




免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM