前幾天一個同事跑過來找我說,我們在廣告素材視頻這塊想做斷點續(xù)傳,就是這次某個視頻緩存到一半,下次不用重頭開始,可以在原來停留得位置開始繼續(xù)下載
.
以提供更好的用戶體驗。
同時說需要我們支持吐素材地址的業(yè)務(wù)接口告訴終端最后修改時間
/
文件簽名(
md5
),用這個用來判斷我當(dāng)前要下的文件有沒有變化,同時告訴終端文件的
Size
大小
.
我一細(xì)想,這個問題壓根不需要通過改變現(xiàn)有接口提供更多的數(shù)據(jù)來做
.
下面從原理實現(xiàn)上簡單說下:
關(guān)鍵點:
對于斷點續(xù)傳,關(guān)鍵點是兩個:
1.
終端知道當(dāng)前的文件和上一次加載的文件是不是內(nèi)容發(fā)生了變化,如果有變化,需要重新從
offset 0
的位置開始下載
2.
終端記錄好上次成功下載到的
offset
,告訴
server
端
,server
端支持從特定的
offset
開始吐數(shù)據(jù)
文件變化感知:
前置業(yè)務(wù)接口方案:
對于關(guān)鍵點
1
,對于決定大部分產(chǎn)品的業(yè)務(wù)場景,可以通過前置業(yè)務(wù)接口解決;這里簡單介紹一下:
對于非下載工具類的產(chǎn)品,如視頻
APP
(奇藝
,
優(yōu)酷),視頻播放前會請求相關(guān)業(yè)務(wù)的信息,主要返回片子叫什么名字,主要演員等等一些列信息,同時會返回一個對于播放最重要的信息
——
播放地址。
播放地址就是我們可以做文章的地方,如果《太子妃第一集》這個片子更新了(被廣電要求減掉某個污的畫面),可以后端系統(tǒng)讓這個業(yè)務(wù)接口吐不同的播放地址
/
一個不同的
url
參數(shù)
(?ver=1.1)/
位置參數(shù)
(#ver1.1)
。這樣純天然的
URL
變化能純天然的讓終端認(rèn)為不是同一個片子,而需要重新加載。
HTPP
標(biāo)準(zhǔn)
ETAG
方案:
沒有業(yè)務(wù)接口的下載工具類的如何解決呢?
下載工具類的沒有前置接口,可以使用
HTTP
的
ETAG
來標(biāo)識是否文件已經(jīng)修改。
ETAG
原理:如果
URL
上的資源內(nèi)容改變,一個新的不一樣的
ETag
就會被分配。用這種方法使用
ETag
即類似于指紋,并且他們能夠被快速地被比較,以確定兩個版本的資源是否相同。
ETag
的比較只對同一個
URL
有意義
——
不同
URL
上的資源的
ETag
值可能相同也可能不同,從他們的
ETag
的比較中無從推斷。
ETAG
是
HTTP
的一個可選字段,且沒有規(guī)范他的實現(xiàn);實際上業(yè)內(nèi)用的比較多的就是使用
MD5
簽名的方式來生成
(linux shell md5sum)
典型用法:
server
端:
Nginx >1.3.3
自帶有
ETAG
的
module ,
當(dāng)然同時也可以在業(yè)務(wù)代碼里
SetHeaders
加一個
ETAG
字段
client
端:
第一次請求時:
String etag = httpURLConnection.getHeaderField("ETag");
ETag: "b428eab9654aa7c87091e"
第二次請求(斷點續(xù)傳時):
httpURLConnection.setRequestProperty(“If-None-Match”, "b428eab9654aa7c87091e");
If-None-Match: "b428eab9654aa7c87091e"
如果
ETag
值匹配,這就意味著資源沒有改變,服務(wù)器便會發(fā)送回一個極短的響應(yīng),包含
HTTP “304
未修改
”
的狀態(tài)。
304
狀態(tài)告訴客戶端,它的緩存版本是最新的,并應(yīng)該使用它。
然而,如果
ETag
的值不匹配,這就意味著資源很可能發(fā)生了變化,那么,一個完整的響應(yīng)就會被返回,包括資源的內(nèi)容,就好像
ETag
沒有被使用。這種情況下,客戶端可以用新返回的資源和新的
ETag
替代先前的緩存版本。
續(xù)傳支持:
對于一個
C/C++
程序員,第一時間會得出一個系統(tǒng)級實現(xiàn)方案:
1.
客戶端傳當(dāng)前的
offset
2. server
端
seek
到文件特定的
offset
開始讀取往
http connection
吐數(shù)據(jù)
不過我們深處在一個開放方案和標(biāo)準(zhǔn)不斷完善的時代,不需要自己實現(xiàn)一個(這也是像我這樣的
C/C++
研發(fā)工程師越來越?jīng)]落的原因)
,
來看看
HTTP
協(xié)議是怎么解決這個問題的:
HTTP
頭
Range
字段:
Range :
用于客戶端到服務(wù)器端的請求,可通過該字段指定下載文件的某一段大小,及其單位。典型的格式如:
Range: bytes=0-499
下載第
0-499
字節(jié)范圍的內(nèi)容
Range: bytes=500-999
下載第
500-999
字節(jié)范圍的內(nèi)容
Range: bytes=-500
下載最后
500
字節(jié)的內(nèi)容
Range: bytes=500-
下載從第
500
字節(jié)開始到文件結(jié)束部分的內(nèi)容
來個簡單粗暴的例子
curl --header "Range: bytes=0-20000" xxx.com/memcache.pdf -o part1
curl --header "Range: bytes=20001-223651" xxx.com/memcache.pdf -o part2
cat part1 part2 >> a.pdf
原文來自:大熊先生