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

浅谈HTTP断点续传原理

断点续传就是从文件上次中断的地方开始重新下载或上传,当下载或上传文件的时候,如果没有实现断点续传功能,那么每次出现异常或者用户主动的暂停,都会去重头下载,这样很浪费时间。所以断点续传的功能就应运而生了。要实现断点续传的功能,需要客户端记录下当前的下载或上传进度,并在需要续传的时候通知服务端本次需要下载或上传的内容片段。

下面来简单介绍 HTTP 断点续传的原理:

其实断点续传的原理很简单,就是在Http的请求上多定义了断点续传相关的HTTP头 Range和Content-Range字段而已,例如!

1.浏览器请求服务器上的一个文件名为test.zip时,请求内容只展示了一些与本文有关的信息

GET /test.zip HTTP/1.1Accept-Language: zh-cnAccept-Encoding: gzip, deflateConnection: Keep-Alive

2.服务器收到请求后,按要求寻找请求的文件,提取文件的信息,然后返回给浏览器,返回信息如下:

200Content-Length=66667777Accept-Ranges=bytesContent-Type=application/octet-stream

为了实现从文件已经下载的地方开始继续下载。所以在客户端传给服务器的时候要多加一条信息--从哪里开始。下面是客户端请求时的请求信息,要求从44445555字节开始。

GET /test.zip HTTP/1.0User-Agent: NetFoxRANGE: bytes=44445555-

上面的请求信息多了一个新的字段RANGE RANGE:bytes=44445555-
这段话的意思就是告诉服务器test.zip这个文件从44445555字节开始传,前面的字节不用传了。服务器收到这个请求以后,返回的信息如下:

206Content-Length=66667777Content-Range=bytes 44445555-66667777Content-Type=application/octet-stream

和第一次服务器返回的信息相比,增加了一行:
Content-Range=bytes 44445555-66667777
返回的代码也改为206了,而不再是200了。

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

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

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