urllib.request 不支持断点续传,需用 requests 手动处理 Range 请求头、'ab' 模式写入、206 状态校验、重定向与异常重试;遇 416 应清空重下。

Python 标准库的 urllib.request 不支持断点续传,必须手动处理 Range 请求头和本地文件偏移写入,否则下载中断后只能重头开始。
用 requests 发起带 Range 头的分段请求
核心是告诉服务器“从第 N 字节开始下载”,这需要先检查本地文件是否已存在,并读取其大小作为起始偏移。服务器返回状态码必须是 206 Partial Content,而非 200 OK;如果返回 200,说明服务器不支持断点续传(比如某些 CDN 或静态托管服务)。
- 先用
HEAD请求获取Content-Length,确认总大小 - 用
os.path.getsize()获取本地已下载字节数,设为start_byte - 构造
headers={'Range': f'bytes={start_byte}-'}发起GET - 检查响应
r.status_code == 206,否则应清空文件重下或报错
以 'ab' 模式打开文件并跳过重复写入
不能用 'wb',否则会覆盖已有内容;也不能用 'a'(文本追加模式),它在二进制场景下行为不可靠。必须用 'ab'(append binary),它天然保证写入位置在文件末尾,且不破坏原有字节。
- 无需手动调用
f.seek()——'ab'模式下f.write()总是从 EOF 开始 - 若本地文件大小与
Range起始值不一致(比如被手动截断),需先os.truncate()或报错退出 - 写入前建议校验
r.headers.get('Content-Range')中的范围是否匹配预期
处理重定向、认证和连接异常的典型陷阱
很多下载链接会 302 跳转,requests 默认跟随重定向,但 Range 头不会自动带到跳转后的请求上,导致续传失败。同时,带认证(如 Bearer Token)的接口,每次重试都需重新携带凭证。
立即学习“Python免费学习笔记(深入)”;
- 设置
allow_redirects=False,手动处理301/302响应中的Location,并在新 URL 上重发带Range的请求 - 网络中断时捕获
requests.exceptions.ConnectionError和Timeout,不要直接退出,而是等待后重试 - 避免无限重试:建议用指数退避(如
time.sleep(min(60, 2 ** retry_count))),并限制最大重试次数
真正难的不是写几行 Range 代码,而是判断什么时候该放弃续传——比如服务器返回 416 Requested Range Not Satisfiable,通常意味着文件已被修改(ETag 变了),此时继续续传会导致文件损坏,必须清空重下。


















