菜鸟笔记
提升您的技术认知

HTTP——断点续传(分块传输)

HTTP——断点续传(分块传输)

断点续传:指的是在上传/下载时,将任务(一个文件或压缩包)人为的划分为几个部分,每一个部分采用一个线程进行上传/下载,如果碰到网络故障,可以从已经上传/下载的部分开始继续上传/下载未完成的部分,而没有必要从头开始上传/下载。可以节省时间,提高速度。

断点续传的用途
有时用户上传/下载文件需要历时数小时,万一线路中断,不具备断点续传的 HTTP/FTP 服务器或下载软件就只能从头重传,所以如果服务器或下载软件具有断点续传能力,允许用户从上传/下载断线的地方继续传送,这样就大大减少了用户的烦恼。

在 Linux/Unix 系统下,常用支持断点续传的 FTP 客户端软件是 lftp

1 HTTP1.1 之后支持端点续传

(1) Range & Content-Range

HTTP1.1 协议(RFC2616)开始支持获取文件的部分内容,这为并行下载以及断点续传提供了技术支持。它通过在 Header 中的两个参数实现,客户端发请求时对应的是 Range ,服务器端响应时对应的是 Content-Range

1)请求头:
Range:浏览器(比如 Flashget 多线程下载时)告诉 WEB 服务器自己想取对象的哪部分。例如:Range: bytes=1173546

2)响应头
Content-Range:用于指定整个实体中的一部分的插入位置,他也指示了整个实体的长度。在服务器向客户返回一个部分响应,它必须描述响应覆盖的范围和整个实体长度。例如,传送头500个字节次字段的形式:Content-Range:bytes0- 499/1234

(2)大体流程概述:

1)客户端下载一个1024K的文件,已经下载了其中512K。

2)网络中断,客户端请求续传,因此需要在HTTP头中申明本次需要续传的片段:

Range:bytes=512000-

3)服务端收到断点续传请求,从文件的512K位置开始传输,并且在HTTP头中增加:

Content-Range:bytes 512000-/1024000

并且此时服务端返回的HTTP状态码应该是206,而不是200。

206 Partial Content: 客户端发起了范围请求,服务器处理成功,返回了由Content-Range指定范围的实体内容。

2 防止续传出错

但是在实际场景中,会出现一种情况,即在终端发起续传请求时,URL对应的文件内容在服务端已经发生变化,此时续传的数据肯定是错误的。如何解决这个问题了?显然此时我们需要有一个标识文件唯一性的方法。在RFC2616中也有相应的定义,比如实现Last-Modified来标识文件的最后修改时间,这样即可判断出续传文件时是否已经发生过改动。同时RFC2616中还定义有一个ETag的头,可以使用ETag头来放置文件的唯一标识,比如文件的MD5值。

(1)响应头:
Etag/Last-Modified作为标记,主要用来验证文件内容是否修改。

Etag:就是一个对象(比如URL)的标志值,就一个对象而言,比如一个html文件,如果被修改了,其Etag也会别修改,所以,ETag的作用跟Last-Modified的作用差不多,主要供WEB服务器判断一个对象是否改变了。比如前一次请求某个html文件时,获得了其 ETag,当这次又请求这个文件时,浏览器就会把先前获得ETag值发送给WEB服务器,然后WEB服务器会把这个ETag跟该文件的当前ETag进行对比,然后就知道这个文件有没有改变了。

Last-Modified:WEB服务器认为对象的最后修改时间,比如文件的最后修改时间,动态页面的最后产生时间等等。例如:Last-Modified:Tue, 06 May 2008 02:42:43 GMT

(2)请求头:
终端在发起续传请求时应该在HTTP头中申明If-Match 或者If-Modified-Since 字段,帮助服务端判别文件变化。

If-ModifiedSince: 如果在If-ModifiedSince字段指定的日期后,资源发生了更新,服务器会接受请求。如果没有更新,即本地cache和服务器资源相同,服务器会发送一个304 Not Modified响应,告知本地的cache页面是最新的。

注意;
在发送HTTP请求时,If-Modified-Since会把浏览器端缓存页面的最后修改时间一起发到服务器去,服务器会把这个时间与服务器上实际文件的最后修改时间进行比较。

  • 如果时间一致,那么返回HTTP状态码304(不返回文件内容),客户端接到之后,就直接把本地缓存文件显示到浏览器中。
  • 如果时间不一致,就返回HTTP状态码200和新的文件内容,客户端接到之后,会丢弃旧文件,把新文件缓存起来,并显示到浏览器中。

If-Match:如果对象的 ETag 没有改变,其实也就意味著对象没有改变,才执行请求的动作,获取文档。

另外RFC2616中同时定义有一个If-Range头,终端如果在续传是使用If-RangeIf-Range中的内容可以为最初收到的ETag头或者是Last-Modfied中的最后修改时间。服务端在收到续传请求时,通过If-Range中的内容进行校验,校验一致时返回206的续传回应,不一致时服务端则返回200回应,回应的内容为新的文件的全部数据。

If-Range: 浏览器告诉 WEB 服务器,如果我请求的对象没有改变,就把我缺少的部分给我,并返回206状态码,如果对象改变了,就把整个对象给我,并返回200。浏览器通过发送请求对象的ETag 或者自己所知道的最后修改时间给 WEB 服务器,让其判断对象是否改变了。总是跟 Range 头部一起使用。