分片上傳- 斷點續傳- 還有秒傳

分片上傳

爲什麼需要分片上傳

如果文件體積比較大,或者網絡條件不好時,上傳的時間會比較長(要傳輸更多的報文,丟包重傳的概率也更大),用戶不能刷新頁面,只能耐心等待請求完成。

分片上傳的核心思想

利用 H5 提供的原生 File 對象,由於 File 對象是特殊類型的 Blob, File 接口也繼承了 Blob 接口的屬性,分片上傳的核心思想就是利用 File 繼承 Blob 接口的 Blob.slice 方法。

Blob.slice 方法可以將我們的文件切分爲多個單個的切片,分片上傳的思想就是利用 slice APi 將文件分割成多個切片,然後利用瀏覽器多進程的特性進行併發上傳。

爲了後端能正確的拼接文件,我們需要爲每一個文件提供一個唯一的標識符,以及標記每一個切片的順序。

標識符一般通過以下兩種方式獲取

根據文件名、文件長度等基本信息進行拼接,爲了避免多個用戶上傳相同的文件,可以再額外拼接用戶信息如 uid 等保證唯一性。

根據文件的二進制內容計算文件的 hash,這樣只要文件內容不一樣,則標識也會不一樣,缺點在於計算量比較大。

document.getElementById('file').addEventListener('change', function () {
    var blobSlice = File.prototype.slice || File.prototype.mozSlice || File.prototype.webkitSlice,
        file = this.files[0],
        chunkSize = 2097152,                             // Read in chunks of 2MB
        chunks = Math.ceil(file.size / chunkSize),
        currentChunk = 0,
        spark = new SparkMD5.ArrayBuffer(),
        fileReader = new FileReader();
    fileReader.onload = function (e) {
        console.log('read chunk nr', currentChunk + 1, 'of', chunks);
        spark.append(e.target.result);                   // Append array buffer
        currentChunk++;
        if (currentChunk < chunks) {
            loadNext();
        } else {
            console.log('finished loading');
            console.info('computed hash', spark.end());  // Compute hash
        }
    };
    fileReader.onerror = function () {
        console.warn('oops, something went wrong.');
    };
    function loadNext() {
        var start = currentChunk * chunkSize,
            end = ((start + chunkSize) >= file.size) ? file.size : start + chunkSize;
        fileReader.readAsArrayBuffer(blobSlice.call(file, start, end));
    }
    loadNext();
});

斷點續傳

即使將大文件拆分成切片上傳,我們仍需等待所有切片上傳完畢,在等待過程中,可能發生一系列導致部分切片上傳失敗的情形,如網絡故障、頁面關閉等。由於切片未全部上傳,因此無法通知服務端合成文件。這種情況下可以通過斷點續傳來進行處理。

主要思路

  1. 在切片上傳成功後,保存已上傳的切片信息。2. 當下次傳輸相同文件時,遍歷切片列表,只選擇未上傳的切片進行上傳。3. 所有文件分片上傳完畢,調用接口通知服務端進行合併。

對於切片信息的保存一般採用以下兩種方式。

可以通過 locaStorage 等方式保存在前端瀏覽器中,這種方式不依賴於服務端,實現起來也比較方便,缺點在於如果用戶清除了本地文件,會導致上傳記錄丟失。

服務端本身知道哪些切片已經上傳,因此可以由服務端額外提供一個根據文件 context 查詢已上傳切片的接口,在上傳文件前調用該文件的歷史上傳記錄。

秒傳

在上傳切片前將文件的基本信息發送至服務端進行驗證,判斷該文件是否需要重新上傳,如果已經上傳就返回上傳結果,實現秒傳。

驗證方法

  1. 文件名。2. 文件最後修改的時間(File 文件對象的一個屬性 lastModified)。3. 文件 hash 值。
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/wjHlAn4eStQHqWUeXwsEBQ