如果我們的網站提供檔案下載下傳的服務,那麼通常我們都希望下載下傳可以斷點續傳(resumable download),也就是說使用者可以暫停下載下傳,并在未來的某個時間從暫停處繼續下載下傳,而不必重新下載下傳整個檔案。
本文将以php為例,簡要介紹實作檔案下載下傳斷點續傳的方法。
原理
斷點續傳的原理還是比較直覺的。
實作
由于部分傳輸不是強制的,伺服器可以支援也可以不支援,是以,我們需要在程式中告訴浏覽器,它請求的資源是否支援部分傳輸。這可以通過設定http的 accept-ranges 響應頭資訊來實作。php代碼如下:
代碼如下:
header('accept-ranges: bytes');
accept-ranges: bytes 告訴浏覽器,該資源支援以位元組為機關的部分傳輸。這個響應頭需要附加在支援部分傳輸的所有資源上。
當接受到一個請求時,我們需要從浏覽器的請求中提取浏覽器具體是在請求資源的哪一個部分。這個資訊是通過 range 請求頭來傳遞的。在php中,它被存儲在$_server['http_range']中。我們需要檢查這個變量是否定義了,如果定義了,則使用該值,否則,就将range設為整個資源。
$range = "0-". ($content_length-1);
if(isset($_server['http_range'])){
$range = $_server['http_range'];
}
接下來,就需要分析 $range 的值,來決定傳回資源的哪一部分内容。可能的取值示例:
100-200 // 第100到第200位元組
500- // 第500位元組到檔案末尾
-1000 // 最後的1000個位元組
這裡需要注意,得到一個range之後,你需要對它的取值進行檢驗,包括:
1.開始位置非負
2.結束位置需要大于開始位置
3.開始位置需要小于檔案長度減一 (因為這裡的位置索引是從0開始的)
4.若結束位置大于檔案長度減一,則需要把它的值設定為檔案長度減一
如果range的取值不合法,則需要終止程式并告知浏覽器:
header('http/1.1 416 requested range not satisfiable');
為了保持文章簡潔,具體的校驗代碼這裡就不提供了。下面假定你已經校驗了range的取值,并得到了 $start 和 $end 兩個變量,分别表示開始位置和結束位置。
接下來要做的就是把檔案的對應部分的内容發送給浏覽器。不過要注意的是,這裡涉及到需要發送多個http響應頭資訊,具體如下:
header('http/1.1 206 partial content');
header("content-range: bytes $start-$end/$filesize");
$length = $end - $start + 1;
header("content-length: $length");
/ 輸出檔案的指定部分 /
這裡的$length需要注意一下,它的取值是本次傳輸的内容的長度,而不是整個檔案的長度。另外需要注意的一點是,這裡的http狀态碼是206,不是200。
總結
檔案下載下傳的斷點續傳實際上是利用了http協定中對傳輸部分檔案的支援。而http協定的這一特性不僅可以用于實作斷點續傳,用戶端程式也可以利用它來實作多線程下載下傳。
在實作斷點續傳的過程中,需要注意正确設定各種http頭資訊。錯誤的頭資訊将導緻使用者下載下傳到的檔案損壞,無法使用。