Python requests下载文件遇ChunkedEncodingError,如何实现断点续传?
流式下载断点续传解决方案
针对Heroku服务器连接不稳定导致的下载中断问题,核心解决思路是利用HTTP的Range请求头实现断点续传——每次断连后,从已经下载的字节位置继续请求剩余数据,而非从头开始重新下载。
实现步骤
- 通过HEAD请求获取目标文件总大小,避免一开始就加载大文件
- 检查本地已下载的文件大小,构造
Range请求头告知服务器从指定字节位置开始传输 - 捕获连接异常并设置重试机制
- 以追加模式打开文件,写入后续下载的数据块
完整代码示例
import requests import os def download_file(url, headers, filename, max_retries=5): save_path = f"./files/{filename}" total_size = 0 downloaded_size = 0 # 获取文件总大小 try: head_res = requests.head(url, headers=headers) head_res.raise_for_status() total_size = int(head_res.headers.get('Content-Length', 0)) print(f"文件总大小: {round(total_size/(1024*1024),3)}MB") except Exception as e: print(f"获取文件信息失败: {str(e)}") return # 读取本地已下载的字节数 if os.path.exists(save_path): downloaded_size = os.path.getsize(save_path) print(f"已下载: {round(downloaded_size/(1024*1024),3)}MB,继续下载剩余部分...") # 已下载完成则直接返回 if downloaded_size >= total_size and total_size != 0: print("文件已下载完成") return retries = 0 while retries < max_retries: try: # 构造断点续传的Range请求头 range_headers = headers.copy() range_headers['Range'] = f'bytes={downloaded_size}-' with requests.get(url, headers=range_headers, stream=True, timeout=30) as res: res.raise_for_status() # 验证服务器是否支持断点续传 if res.status_code != 206 and downloaded_size > 0: print("服务器不支持断点续传,将从头开始下载") downloaded_size = 0 os.remove(save_path) continue with open(save_path, 'ab') as file: for chunk in res.iter_content(chunk_size=8192): if chunk: file.write(chunk) downloaded_size += len(chunk) print(f"已下载: {round(downloaded_size/(1024*1024),3)}MB / {round(total_size/(1024*1024),3)}MB", end="\r") # 验证下载完整性 if os.path.getsize(save_path) == total_size or total_size == 0: print("\n下载完成") return else: print(f"\n下载未完成,已下载{downloaded_size}字节,目标{total_size}字节,重试中...") retries += 1 except requests.exceptions.RequestException as e: print(f"\n连接中断: {str(e)},重试中...") retries += 1 print(f"已重试{max_retries}次仍失败,请检查网络或服务器状态") # 使用示例 # download_file("你的目标URL", {"自定义请求头"}, "目标文件名.mp4")
关键细节说明
- Range请求头:格式为
bytes=start-,服务器会返回从start字节到文件末尾的内容,响应状态码为206(Partial Content) - 追加写入模式:用
'ab'模式打开文件,确保已下载的内容不会被覆盖 - 重试机制:设置最大重试次数,避免无限循环等待
- 完整性验证:下载结束后对比本地文件大小与服务器返回的总大小,确保文件完整
- 兼容性处理:如果服务器不支持Range请求,自动切换为从头下载
注意事项
- 确认目标服务器支持Range请求(Heroku托管的静态文件或多数API均支持)
- 若服务器响应无
Content-Length(如动态生成内容),可移除总大小验证逻辑,持续下载至连接正常结束 - 可根据网络状况调整
chunk_size和timeout参数
内容的提问来源于stack exchange,提问作者Jyotirmay
相关产品推荐
相关产品推荐

