移動開發中,為了減小包體積,很多檔案都會通過雲端下發的方式服務使用者。檔案下載下傳中,經常會把Content-Length作為下載下傳進度的重要參數,但是不同的伺服器對待檔案請求的方式不一樣,可能存在Content-Length為-1或不準确的問題,導緻下載下傳進度不準确,影響使用者體驗。
1.什麼是Content-Length
在HTTP協定中,Content-Length用于描述HTTP消息實體的傳輸長度the transfer-length of the message-body。在HTTP協定中,消息實體長度和消息實體的傳輸長度是有差別,比如說gzip壓縮下,消息實體長度是壓縮前的長度,消息實體的傳輸長度是gzip壓縮後的長度。
2.Content-Length為什麼不靠譜(content-length擷取的大小與實際檔案大小不一緻的原因)
下面我們來分析幾種Content-Length的幾種異常情況:
2.1.gzip壓縮問題
引用官方文檔的描述:
By default this implementation of HttpURLConnection requests that servers use gzip compression. Since getContentLength() returns the number of bytes transmitted, you cannot use that method to predict how many bytes can be read from getInputStream(). Instead, read that stream until it is exhausted: when read() returns -1. Gzip compression can be disabled by setting the acceptable encodings in the request header。
在預設情況下HttpURLConnection 使用 gzip方式擷取(python requests.get(url) 方式也預設使用gzip方式),檔案 getContentLength() 這個方法(python用response.headers.get('content-length', 0))
,每次read完成後可以獲得,目前已經傳送了多少資料,而不能用這個方法擷取需要傳送多少位元組的内容,當read() 傳回 -1時,讀取完成。
擷取的content-length 值也是目标檔案壓縮後的值,一般比實際的檔案大小要小(對文本形式的檔案,txt、xml等),對zip及exe檔案沒有影響,其他格式的未進行測試過。
是以要取得正确的檔案長度,要求http請求不要gzip壓縮。
conn .setRequestProperty("Accept-Encoding", "identity")
python requests 中這樣設定:
requests.get(_my_url, stream=True,headers={"Accept-Encoding": "identity"}
2.2.請求頭的問題
一般可能是請求頭的問題 導緻被伺服器拒絕通路了
conn.setRequestProperty("User-Agent", " Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/37.0.2062.120 Safari/537.36")
2.3.伺服器端無Content-Length
如果服務端沒有設定Content-Length, 那麼用戶端擷取Content-Length時就是-1
3.http協定之Content-Length
對于http的請求傳回結果要進行内容的長度校驗主要有兩種方式,二者互斥使用:
1.用戶端在http頭(head)加Connection:keep-alive時,伺服器的response是Transfer-Encoding:chunked的形式,通知頁面資料是否接收完畢,例如長連接配接或者程式運作中可以動态的輸出内容,例如一些運算比較複雜且需要使用者及時的得到最新結果,那就采用chunked編碼将内容分塊輸出。
2.除了如1所述之外的情況一般都是可以擷取到Content-Length的。
在具體的HTTP互動中,用戶端是如何擷取消息長度的呢,主要基于以下幾個規則:
1、Content-Length如果存在并且有效的話,則必須和消息内容的傳輸長度完全一緻。(經過測試,如果過短則會截斷,過長則會導緻逾時。)
2、如果存在Transfer-Encoding(重點是chunked),則在header中不能有Content-Length,有也會被忽視。
3、如果采用短連接配接,則直接可以通過伺服器關閉連接配接來确定消息的傳輸長度。(這個很容易懂)
結合HTTP協定其他的特點,比如說Http1.1之前的不支援keep alive。那麼可以得出以下結論:
1、在Http 1.0及之前版本中,content-length字段可有可無。
2、在http1.1及之後版本。如果是keep alive,則content-length和chunk必然是二選一。若是非keep alive,則和http1.0一樣。content-length可有可無
4.如何正确下載下傳檔案
引用官方文檔的話:
read that stream until it is exhausted: when read() returns -1
numRead = bis.read(buffer, offset,BUFFER_SIZE - offset);
if (numRead == -1) {
// 已經沒有資料了,退出循環
if (offset > 0) {
// buffer未填充滿,但已經沒資料了,則寫入檔案
fileOutputStream.write(buffer, 0, offset);
}
break;
}
作者:敗家子2019
連結:https://www.jianshu.com/p/57f6cc0d6e48
來源:簡書
著作權歸作者所有。商業轉載請聯系作者獲得授權,非商業轉載請注明出處。