先說說斷點續傳的原理:這是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的狀態代碼。
附圖一張,簡述流程。
補記:有一次被問起如何在原生的Android手機上暫停一個下載任務,回頭再斷點續傳。我想是不是可以在下載過程中將手機訊號關閉,下次再開啟手機訊號時,那個下載任務就可以自動接著續傳了(當然前提是伺服器支援)...這個用例沒多大實用價值,懶得實測了。
原文連結:http://blog.csdn.net/Oneway102/article/details/6060961