說說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的狀態碼。

附圖一張,簡述流程。


補記:有一次被問起如何在原生的Android手機上暫停一個下載任務,回頭再斷點續傳。我想是不是可以在下載過程中將手機信號關閉,下次再打開手機信號時,那個下載任務就可以自動接着續傳了(當然前提是服務器支持)...這個用例沒多大實用價值,懶得實測了。

轉自:http://dev.10086.cn/cmdn/wiki/index.php?doc-view-4957.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章