踩坑Webuploader視訊上傳

janto007發表於2019-03-02

背景

由於我司業務關係,需實現相容IE8+瀏覽器的視訊上傳功能,且支援多選斷點上傳。故藉助Baidu WebFE(FEX)團隊開發的webuploader檔案上傳外掛實現此業務功能。

檔案上傳的一般聯調步驟

1.js端認證(主要是判斷視訊是否已存在,若已存在,返回視訊已上傳的檔案大小,只需要判斷一次):

  • 第一步:計算視訊檔案的md5,視訊檔案越大、計算md5的時間越久

  • 第二步:獲取視訊檔案的總大小

  • 第三步:把視訊名稱、檔案總大小、視訊檔案的md5字串傳輸到tokenUrl

2.返回json的引數:

  • success:驗證是否成功

  • fileMd5:視訊檔案md5

  • start:已上傳的大小(沒上傳過的返回0,已上傳部分則返回對應已上傳的大小值,例如:30000位元組,已上傳20000位元組,則返回20000)

3.驗證通過後,js端上傳(視訊檔案大的,分割的次數也越多)

  • 第一步:根據視訊檔案的總大小、設定每次分割視訊流的大小
  • 第二步:把視訊檔案的md5字串、
  • 視訊已上傳的大小值start(第一次是根據JS端認證的填寫,第二次是根據上一次返回的填寫)、分割的視訊流傳輸到upUrl
  • 返回json的引數:
  • success:驗證上傳該段視訊流是否成功
  • start:已上傳的大小

外掛配置解析

HTML部分

首先準備dom結構,包含存放檔案資訊的容器、選擇按鈕和上傳按鈕三個部分。

<!--視訊列表顯示-->
<ul class="resources_body_modal_add_list">
{#list queuedList as item}
<li class="resources_body_modal_add_list_item">
  <div class="resources_body_modal_add_list_item_hd" style="background-image: url({item.gvdPic})"></div> 
  <div class="resources_body_modal_add_list_item_bd">
    <input type="text" name="" placeholder="此處為視訊名稱,點選可修改" class="form-control" value={item.name} on-blur={this.updateName(item_index, $event)} />
  </div>
  <span class="resources_body_modal_add_list_item_icon" on-click={this.deleteQueuedFile(item_index)}>x</span> 
  <div class="resources_body_modal_add_list_item_bar">
    <div class="resources_body_modal_add_list_item_bar_progress"></div>
  </div>
</li> 
{/list}
</ul>
<!--檔案上傳按鈕-->
<div class="resources_body_modal_add_field">
<div class="resources_body_modal_add_field_cell">
    <!--配置所用id-->
  <div id="filePicker" class="resources_body_modal_add_field_cell_icon" r-hide={queuedList.length == queuedLimit}>+</div>
  <p class="g-mb20" r-hide={queuedList.length == queuedLimit}>點選上傳視訊</p>
  <p r-hide={queuedList.length} class="js-empty">每次最多上傳{queuedLimit}個,單個視訊不超過4G</p>
  <p r-hide={!queuedList.length} class="js-full">
    已選擇
    <span class="js-uploadLength"></span>個,
    <span class="js-uploadLeft"></span>
  </p>
</div> 
</div> 
複製程式碼

初始化webuploader

uploader = WebUploader.create({
    resize: false, // 不壓縮image     
    swf: base_URL + `jslib/WebUploader/Uploader.swf`, // swf檔案路徑
    method: "post",
    sendAsBinary : true,//檔案上傳二進位制流
    fileNumLimit: 10,//驗證檔案總數量, 超出則不允許加入佇列
    fileSingleSizeLimit: 4*1024*1024*1024,//驗證單個檔案大小是否超出限制, 超出則不允許加入佇列
    server: upload_URL,// 檔案接收服務端
    pick: {
        id: `#filePicker`, //這個id是你要點選上傳檔案按鈕的外層div的id  
        multiple : true //是否可以批量上傳,true可以同時選擇多個檔案  
    },    
    chunked: true,//是否要分片處理大檔案上傳
    threads: true, //上傳併發數
    chunkSize:3*1024*1024, //分片上傳,每片2M,預設是5M
    prepareNextFile: true,//上傳當前分片時預處理下一分片 
    //auto: false //選擇檔案後是否自動上傳
    chunkRetry : 1, //如果某個分片由於網路問題出錯,允許自動重傳次數
    duplicate: false, //重複選擇
    // runtimeOrder: `html5, flash`
    accept: {
        extensions: `avi,wmv,rm,rmvb,mov,mkv,flv,mp4,f4v,3gp,ts,wma,wav,aac`,
        mimeTypes: `.avi,.wmv,.rm,.rmvb,.mov,.mkv,.flv,.mp4,.f4v,.3gp,.ts,.wma,.wav,.aac`
    }//視訊檔案字尾
});

複製程式碼

監聽分塊上傳過程中的三個時間點

WebUploader.Uploader.register({
    "before-send-file":"beforeSendFile",  
    "before-send":"beforeSend",  
    "after-send-file":"afterSendFile",  
},{  
    //時間點1:所有分塊進行上傳之前呼叫此函式  
    beforeSendFile:function(file){
        var deferred = WebUploader.Deferred();  
        //1、計算檔案的唯一標記,用於斷點續傳  
        (new WebUploader.Uploader()).md5File(file,0,2*1024*1024)  
            .progress(function(percentage){  
            })  
            .then(function(val){  
                fileMd5=val;  
                //獲取檔案資訊後進入下一步  
                deferred.resolve();  
            });  
        return deferred.promise();  
    },  
    //時間點2:如果有分塊上傳,則每個分塊上傳之前呼叫此函式  
    beforeSend:function(block){
        var deferred = WebUploader.Deferred();
        if(videoAdd[block.file.id] > block.start){
            // 分塊存在,跳過    
            deferred.reject();    
        }else{    
            // 分塊不存在或不完整,重新傳送該分塊內容    
            this.owner.options.formData={
              start: block.start,//設定視訊上傳的start點
              fileMd5: videoMd5[block.file.id]//設定視訊上傳的唯一標識MD5
            }

            deferred.resolve();    
        } 
        return deferred.promise();  
    },  
    //時間點3:所有分塊上傳成功後呼叫此函式  
    afterSendFile:function(file, response){
        //分塊上傳成功,執行成功回撥
        successHandler(file, response, fileArr);
    
    }  
});  
複製程式碼

顯示使用者選擇

監聽fileQueued事件來實現

uploader.on( `fileQueued`, function( file ) {
    // 符合條件的視訊才會加進佇列,包括大小,字尾,數量限制
    //設定檔案loading狀態
    uploader.md5File(file)
    // 及時顯示進度
        .progress(function(percentage) {
            //可根據percentage顯示獲取檔案資訊時的進度
        })
        //完成
        .then(function(md5Val){
        //開始執行上傳操作
        })
})
複製程式碼

顯示檔案上傳進度

//顯示檔案上傳進度
uploader.on( `uploadProgress`, function(file, percentage) {
  var $uploading= $(`.js-uploading-`+file.id);
  var progressWid= (percentage*100)+`%`;
  $uploading.find(`.js-bar`).width(progressWid);
});
複製程式碼

檔案上傳失敗處理

//檔案上傳失敗處理
uploader.on( `uploadError`, function(file, reason) {
  $(`.js-uploading-`+file.id).addClass(`hidden`);
  uploader.cancelFile(file);//清空佇列佔位
});
複製程式碼

選擇檔案錯誤處理

uploader.on(`error`, errorHandler);
複製程式碼

至此視訊上傳功能,基本能實現。

tips:

  • 彈出窗顯示上傳按鈕功能時,需注意初始化的時間以及銷燬 webuploader 例項,應當在modal顯示後,以及隱藏後回撥處理。
  • 當實現多選檔案上傳時,需匹配好上傳分塊時的引數
  • IE8瀏覽器彈窗顯示檔案選擇按鈕可能會出現flash錯誤問題,只需在彈窗顯示完全時,用樣式調整即可

相關文章