利用Python实现HTTP断点下载功能

背景

最近在家要下载一个比较大的镜像文件,因为网络太差,每次都是下载到中间就停了,文件就下载失败。我用的是 chrome 自带的下载功能,就这样重试了4-5 次,每次都以失败告终。可恨的是,有时候下载到 80% - 90%,失败了还要从头重来。

后来我就想到 wget 命令行,上网搜了一下,发现 wget 是自带断点下载功能的。也就是说,如果中间连接断开,可以直接从已经下载好的地方继续开始。然后,直接使用 wget 搞定了任务。

如果之前已经有了一个下载部分的文件,也可以使用 wget 的 -c 命令,来继续下载。 可以参考 nixCraft 上一篇文章 Wget: Resume Broken Download

琢磨

按说完事之后,我也就该放心啦。文件也下载完了,你还有啥可惦记的呢?可是我心里一直有个疙瘩:HTTP 协议不是无状态的吗?重发的请求,是怎么告诉服务器端,我只要某一段数据的呢?应用程序有事怎么把不同的数据接起来的呢?

然后,我就继续搜索,发现 HTTP 断点续传秘密所在:Range 头部字段。

解释

断点下载,通俗一点说,就是客户端告诉服务器端:我已经下载了前面长度为 n 的内容, 请从 n+1 个数据给我传过来,不用从 0 开始重新传。

HTTP 1.1 版本中,有个对应的实体头部做这件事情,那就是RangeRange 指定要请求实体(entity)的范围,和多数的程序规范一样,它也是从 0 开始计数的。比如前面已经下载了 500 bytes 的内容,要请求 500 bytes 以后的内容,只要在 HTTP 请求的头部加上 Range: bytes=500- 就可以啦。

Range 有几种不同的方式来限定范围:

  • 500-900:指定开始到结束这一段的长度,记住 Range 是从 0 计数 的,所以这个是要求服务器从 501 字节开始传,一直到 901 字节结束。这个一般用来特别大的文件分片传输,比如视频。
  • 500-:从 501 bytes 之后开始传,一直传到最后。这个就比较适合用于断点续传,客户端已经下载了 500 字节的内容,麻烦把后面的传过来
  • -500:这个需要注意啦,如果范围没有指定开始位置,就是要服务器端传递倒数 500 字节的内容。而不是从 0 开始的 500 字节。。
  • 500-900, 1000-2000:也可以同时指定多个范围的内容,这种情况不是很常见

客户端发出这样的请求,也要服务器端响应和支持这个功能。前面也提到过,这个实体头部是 HTTP 1.1 版本才添加的,所以有些 HTTP 服务端使用比较老的版本可能不支持。

如果服务端支持的话,那么这个响应里也要带一个 content-range 的字段。比如客户端使用的是 Range: bytes=1024-,那么对应的服务端返回头部会包括类似 content-range: bytes 1024-439714/439715 的内容。这个意思就是说,我知道啦,我会从只传递 1024 - 439714 范围的内容,而整个文件的大小是 439715 字节。而且,这个时候响应的 status code 一定是 206,关于 206 的解释可以查看 w3 官网上的说明。 。 如果真是这样也就皆大欢喜啦,但是可能出现两种异常情况:

不支持

服务端返回的响应头部没有 content-range 字段,表明服务端忽略了请求里 range 字段。可能是因为服务端不支持这个功能,那么也没办法,只能从头开始下载。 注:目前大多数 HTTP 都支持这个功能,所以这个情况也很少见

支持是支持,但还是给我从头传

服务端返回的响应头部包含了 content-range,但还是从 0 开始重新下载的。这个就是服务端实现比较严格,考虑到了这个文件可能会被修改的情况。

什么意思?考虑一下这个情况:昨天我下载某个文件,下了一半,今天使用 wget -c 接着下。但问题是:中间某个时间点,这个文件被更新了!URL 没变,但是文件内容变啦。如果我接着往后下,然后把之前的内容和新下的内容和在一起,很可能就不是一个正常的文件啦,没有办法打开。这个情况比从头开始下载还要糟糕:辛辛苦苦下载完,结果是不能用的。

如果服务端要下载的文件,或者其他资源是可变的。就要有一个办法来标识文件或者资源的唯一性,就是说我之前下载的到底是哪个版本的,和现在版本是不是一致的。HTTP 协议里有两个办法可以来做这件事,当然也就是两个头

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值