直接用requests.get()下载大文件会失败,因默认加载全部响应体至内存易oom,且无分块、无状态保存,中断即重来;关键须确认服务端返回accept-ranges: bytes头,否则range请求无效。

为什么直接用 requests.get() 下载大文件会失败
因为默认请求是完整响应体,没做分块、没存中间状态,网络中断或进程退出就全得重来。更关键的是,服务端未必支持断点续传——必须先确认它返回了 Accept-Ranges: bytes 响应头,否则 Range 请求会被忽略,返回 200 而非 206。
怎么用 Range 头发起续传请求
核心是手动构造 headers,告诉服务端“我要从第 N 字节开始下载”。注意起始字节从 0 开始计数,且范围闭合(Range: bytes=1024- 表示从第 1024 字节到末尾)。
- 首次下载:不带
Range,或设为bytes=0-;记录响应头中的Content-Length - 续传时:读取本地已下载文件大小作为
start_byte,设置headers={'Range': f'bytes={start_byte}-'} - 必须检查响应状态码:收到
206 Partial Content才说明服务端支持且生效;若返回200,说明Range被忽略,需中止或降级处理
示例片段:
图片提示词生成器?不止如此。 马甲系统 —— 把脑海中的画面,翻译成AI能理解的专业表达。 用得越多,它越懂你:首次需要多问几句确认方向,用久了几乎一说就懂。 用得越多,它越快:缓存机制让后续对话越来越省。 RAG进化:成功案例持续入库,越跑越聪明。 输入「新手指南」查看完整功能介绍
headers = {'Range': 'bytes=1024-'}
r = requests.get(url, headers=headers, stream=True)
if r.status_code != 206:
raise RuntimeError(f"Server doesn't support resume: {r.status_code}")
怎么安全地追加写入并校验文件完整性
不能用普通 'w' 模式覆盖,也不能在未校验前就信任本地文件长度。重点在于打开模式和写入位置控制。
- 始终用
'rb+'模式打开文件,用.seek(start_byte)定位到末尾再写入 - 写入前建议先
os.path.getsize()校验本地文件大小是否等于start_byte,防止残留脏数据 - 下载完成后建议比对
Content-Range响应头里的总长度(如bytes 1024-4095/8192中的8192)与本地文件大小是否一致 - 如需强一致性,可额外计算并比对服务端提供的
ETag或Content-MD5(若有)
常见坑:重定向、认证、连接复用导致的续传失效
很多看似正常的请求,实际因中间代理或服务端逻辑破坏了续传链路。
- 重定向(302/307)后,
Range头可能丢失,requests默认会重发但不携带原Range;需手动禁用自动重定向:allow_redirects=False,自己处理跳转并透传头 - 带认证(如
Authorization)时,某些服务对Range请求校验更严,可能返回 401;确保认证凭据在每次请求中都存在 - 复用 session 时,记得关闭连接池的过期连接:
session.headers.update({'Connection': 'close'}),避免旧连接缓存干扰新 Range 请求
断点续传真正难的不是发请求,而是把服务端行为、网络中间件、本地文件状态三者对齐。哪怕一个 Content-Range 解析错位,后续所有校验都会失效。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!










