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



html

相關文章
相關標籤/搜索