天天看點

說說Android上的斷點續傳下載下傳

先說說斷點續傳的原理:這是HTTP 1.1協定的一部分,并不需要用戶端特意去做多麼複雜的事情。以前我曾經看過一個機關的技術标書,其中有下載下傳的斷點續傳這一要求,給出的offer居然還挺高的...

簡單的說,隻要利用了​​HTTP協定​​​(​​http://www.ietf.org/rfc/rfc2616.txt​​)中的如下字段來和伺服器端互動,就可以實作檔案下載下傳的斷點續傳:

Range : 用于用戶端到伺服器端的請求,可通過該字段指定下載下傳檔案的某一段大小,及其機關。典型的格式如:

Range: bytes=0-499 下載下傳第0-499位元組範圍的内容

Range: bytes=500-999  下載下傳第500-999位元組範圍的内容

Range: bytes=-500  下載下傳最後500位元組的内容

Range: bytes=500-  下載下傳從第500位元組開始到檔案結束部分的内容(這是最常用的一種格式)

Range: bytes=0-0,-1  下載下傳第一以及最後一個位元組的内容(這個看上去有點變态...)

Accept-Ranges : 用于伺服器端到用戶端的應答,用戶端通過該字段可以判斷伺服器是否支援斷點續傳(注意RFC中注明了這一部分并不是必須的)。格式如下:

Accept-Ranges: bytes  表示支援以bytes為機關進行傳輸。

Accept-Ranges: none  表示不支援

Content-Ranges : 用于伺服器端到用戶端的應答,與Accept-Ranges在同一個封包内,通過該字段指定了傳回的檔案資源的位元組範圍。格式如下:

Content-Ranges: bytes 0-499/1234  大小為1234的檔案的第0-499位元組範圍的内容

Content-Ranges: bytes 734-1233/1234  大小為1234位元組的檔案的第734-結尾範圍的内容

據此我們可以知道,斷點續傳這個功能是需要用戶端和伺服器端同時支援才能完成。

Android平台面向開發者提供了DownloadManager這個服務(service),可以用來完成下載下傳,同時異步地得到下載下傳進度的實時更新提示。原生的浏覽器,Android Market以及GMail等用戶端都使用了該接口。該接口也部分的提供了斷點續傳功能:如果在下載下傳過程中遇到網絡錯誤,如信号中斷等,DownloadManager會在網絡恢複時嘗試斷點續傳繼續下載下傳該檔案。但不支援由使用者發起的暫停然後斷點續傳。

要擴充該功能也不難,隻要為下載下傳任務新增一種狀态(類似paused_by_user),以及相關邏輯即可,這裡暫不贅述,把話題引到一些常見問題上。

1. 關于ETag

RFC中的定義有些抽象,簡單的說,ETag可以用來辨別/保證檔案的唯一性或完整性,你可以把它看作是伺服器為某個檔案生産的唯一辨別值,每次檔案有更新該值就會變化。通過這種機制用戶端可以檢查某個檔案在斷點續傳(當然它不僅僅用于斷點續傳)的前後是否有所改動:如果ETag改變了就應該重新下載下傳整個檔案以保證它的完整性。

但是在現實環境中,有一些伺服器并不傳回ETag字段,同時它又是支援斷點續傳的,這種情況下原生的Android就會認為伺服器端不支援斷點續傳。這應該不是什麼bug,僅僅是這麼實作而已。還有更麻煩的情況是,有些伺服器給了錯誤的ETag,但檔案是從未更改的,這時候要想從用戶端修改這個“bug”,估計隻能忽略ETag值了。

2. 關于HTTP 206

RFC中定義了斷點續傳時伺服器端的應答情況:如果支援且傳回的内容如請求所要求的那樣,是該檔案的一部分,則使用HTTP 206狀态碼;如果不支援,或需要傳回整個檔案,則使用HTTP 200狀态碼。但是現實網絡中有些伺服器不管三七二十一,都傳回200。沒辦法,如果還是想從用戶端來修改這個“bug”,那就多做一些判斷處理吧:如果伺服器指定了“Content-Ranges”,就忽略HTTP 200的狀态碼。

附圖一張,簡述流程。