⽂件下载Content-Length详解
移动开发中,为了减⼩包体积,很多⽂件都会通过云端下发的⽅式服务⽤户。⽂件下载中,经常会把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的⼏种异常情况:
ip压缩问题
引⽤官⽅⽂档的描述:
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⽅式获取,⽂件 getContentLength() 这个⽅法,每次read完成后可以获得,当前已经传送了多少数据,⽽不能⽤这个⽅法获取需要传送多少字节的内容,当read() 返回 -1时,读取完成。
因此要取得正确的⽂件长度,要求http请求不要gzip压缩。
conn .setRequestProperty("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
gzip是什么文件夹numRead = ad(buffer, offset,BUFFER_SIZE - offset);
if (numRead == -1) {
// 已经没有数据了,退出循环
if (offset > 0) {
// buffer未填充满,但已经没数据了,则写⼊⽂件
fileOutputStream.write(buffer, 0, offset);
}
break;
}
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论