利用 js 純前端實現多線程下載及斷點續傳
多線程下載、斷點續傳在各類網盤中已經屢見不鮮了,但是那些基本都是桌面端軟件,就拿百度網盤來說,其網頁端也並沒有支持多線程下載,而是採用了瀏覽器默認的下載方式,這種瀏覽器默認提供的下載方式確實很好用,但是十項如果我們要下載的文件非常大,達到了以 G 計數的大小,那麼這種下載方式的弊端就展現出來了,
1、下載速度慢,可能要 1 個小時左右才能下載完。
2、雖然說瀏覽器實現了斷點續傳,但是如果下載到一半出現異常,還是有幾率會讓我們從頭重下,這種體驗未免有些糟糕。
那麼我們如果用前端技術來助力多線程下載和斷點續傳呢?可能很多人會覺得這個一定需要後端配合我們纔可能做到,但是我今天想告訴你,我們要用純前端技術加一點服務器的知識實現多線程下載和斷點續傳,完全不用後端的配合,在開始之前我們需要先了解一下 HTTP 的範圍請求。
一、是否支持範圍請求
HTTP 本身是一種無狀態的 “鬆散” 協議,在經歷了很多版本的迭代之後, 在 HTTP/1,1(RFC2616)之後支持了範圍請求,並明確聲明瞭響應頭 accept-ranges 用於標記是否支持範圍請求,而他只有一個可選參數 bytes,
如果下載文件時響應頭返回了 accept-ranges:bytes, 說明該文件支持範圍請求,我們可以對其做多線程下載,這裏注意不要再服務端強制加響應頭 accept-ranges:bytes,雖然頭能加上去,但是會出現一個很詭異的問題,這個我們後面再說。
二、如何使用範圍請求實現下載?
根據上面的知識我們已經知道了如何判別一個文件是否支持範圍請求,那麼我們如何在請求資源的時候使用它呢?
我們知道文件其實最終都是存儲在磁盤或內存中的字節組成的,而對於每一個文件我們都可以將其分割爲以字節爲單位的小塊,我們可以將文件根據一定的步長或者範圍劃分成 n 多小片,然後分別請求這些小片段得到片段內的字節,在所有小片都下載完成後,合併這些字節不就可以得到一個完整的文件了嗎?
爲了迎合 響應頭 accept-ranges: bytes,HTTP/1.1 同時定義了 ranges 請求頭用於直接請求文件的範圍,其範圍取值在 0-content-length(也是一個響應頭) 之間,使用字符 - 分割。
range 根據需要可以靈活選用以下幾種不同的方式來限定範圍。
1、0-100:指定開始和結束的範圍,指取 0-100 範圍內的數據
2、-100:無開始區間,指取最後 100bytes 的數據
3、100-:指定開始區間,無結束區間,指從 100bytes 一直取到文件結束
4、0-100,101-200:指定多個範圍區間,這種瞭解一下就好了
使用時我們只需要增加請求頭 ranges:bytes=0-100 就行了。
當我們使用 range 請求頭來請求文件時,服務端也會響應 content-range 來標記響應實體的內容範圍。
格式如上圖所示,Content-Range: bytes 0-100/8003979,0-100 表示請求的範圍,8003978 表示文件的總大小,而這裏需要大家注意狀態碼是 206 Partial Content,不是 200,回到上面我們提到的強制加響應頭 accept-ranges: bytes 會導致一個詭異的問題,就是這邊的狀態碼會是 200 而不是 206,整個流程看不出問題,但最終合成的文件大小會是原始文件大小的 n 倍,n 等於分片數的大小。關於 206 狀態碼的結束大家可以參考:https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Status/206。
三、範圍請求助力多線程下載及斷點續傳
知道了範圍請求實現多線程下載就很簡單了,無非根據文件大小和指定的分片大小,將文件分片,實現一個多線程下載隊列,多線程並行下載文件分片,在所有分片下載完成後合併文件就好了。至於斷點續傳不過就是一些優化體驗的手段,記錄下下載失敗的分片,重新下載跳過已經正確下載的分片,只下載失敗的分片,最終在所有分片下載完成後合成文件。
四、實現過程中可能遇到的一些問題
1、很多朋友可能會想,我把一個幾 G 的文件下載到內存中會不會導致瀏覽器爆掉,經過調研完全就是多慮了,範圍請求下來的文件瀏覽器做了優化並沒有放在內存中,而是以臨時文件的形式存在了磁盤上,而且就算網站常用的資源文件,也不是所有都會放在內存中的,瀏覽器會根據文件可能使用的頻率將文件放在內存中或者存在磁盤中。
2、很多人可能會問分片下載完成後怎麼合併文件?怎麼下載文件?其實我們下載完成後就可以得到文件分片的 blob,將這些文件分片的 blob 就可以合併爲大文件的 blob,通過 blob 生成 url,然後觸發瀏覽器默認的下載就可以了,這裏的瀏覽器的默認下載很非常快,大家不必擔心。
結語
封裝了一個通用類用於實現了多線程下載隊列、和斷點重下機制,下載進度和簡單的時間預測,源碼下載:https://demo.deanhan.cn/batch-download.html
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/fyRSauHL783p6gnRu4K74A