应使用Retry策略配合HTTPAdapter实现可控重试,支持断点续传(Range请求)、双地址探测真实断网、threading.Event控制生命周期,并定期重建Session以应对配置变更。

用 requests + 重试机制处理网络中断
直接靠单次 requests.get() 肯定不行,断网时会抛出 requests.exceptions.ConnectionError 或 requests.exceptions.Timeout。必须包裹重试逻辑,且不能无脑循环——得控制次数、间隔和退出条件。
推荐用 urllib3.util.retry.Retry 配合 requests.adapters.HTTPAdapter,它比手写 while True 更可靠,能区分可重试与不可重试错误(比如 404 不该重试,但连接拒绝可以)。
- 设置
total=5控制总重试次数,backoff_factor=1启用指数退避(第1次等1秒,第2次等2秒,第3次等4秒…) - 显式指定
allowed_methods=["HEAD", "GET", "OPTIONS"],避免 POST 等非幂等请求被误重试 - 务必捕获最终失败:即使重试耗尽,仍要抛出异常或返回
None,否则任务会静默卡死
from requests.adapters import HTTPAdapter
from urllib3.util.retry import Retry
import requests
session = requests.Session()
retry_strategy = Retry(
total=5,
backoff_factor=1,
allowed_methods=["HEAD", "GET", "OPTIONS"],
status_forcelist=[429, 500, 502, 503, 504],
)
adapter = HTTPAdapter(max_retries=retry_strategy)
session.mount("http://", adapter)
session.mount("https://", adapter)
try:
resp = session.get("https://example.com/large-file.zip", timeout=(3.05, 27))
except requests.exceptions.RequestException as e:
print(f"下载彻底失败:{e}")
大文件下载中断后续传(Range 请求)
单纯重试整个下载,在网络不稳定+大文件场景下极低效。必须支持断点续传,核心是利用 HTTP Range 头和服务器返回的 Accept-Ranges: bytes 响应头。
关键不是“能不能续”,而是“怎么安全判断该从哪续”。不能只依赖本地文件大小——可能写入一半崩溃导致末尾数据损坏。
立即学习“Python免费学习笔记(深入)”;
让 macOS 自动化像说话一样简单 —— 用代码控制你的 Mac,无需学习 AppleScript 系统要求 macOS 14+ (Sonoma) Python 3.9+ 需要开启:辅助功能 + 屏幕录制权限
- 先用
HEAD请求获取文件总大小(Content-Length),再对比本地已存大小 - 若本地文件存在且大小 > 0,用
Range: bytes={start}-发起带范围的GET,并检查响应状态码是否为206 Partial Content - 用二进制追加模式(
"ab")写入,避免覆盖已有内容;写入前建议校验最后几个字节(如魔数)确认完整性
检测真实断网而非临时超时
重连逻辑容易把短暂高延迟误判为断网,频繁重试反而加重网络负担。需要更精准的连通性判断。
不要只依赖目标域名的请求失败——可能是服务端问题。应额外探测一个稳定兜底地址(如 https://cloudflare-dns.com/dns-query 或 http://1.1.1.1),用极短超时(timeout=(0.5, 0.5))快速验证本机网络栈是否存活。
- 若目标地址失败但兜底地址成功 → 服务端问题,不应重连,应降级或告警
- 若两者均失败 → 真实断网,启动重连流程(可配合
os.system("ping -c1 1.1.1.1")做二次确认) - 避免在循环重试中每次都调用系统命令,应设最小探测间隔(如 5 秒)
用 threading.Event 或信号控制重连生命周期
自动重连不能变成永动机。用户主动取消、程序退出、磁盘满、认证过期等情况,都必须能及时终止重试。
硬编码 time.sleep() 和 while 循环很难响应外部中断。推荐用 threading.Event 作为全局开关,或监听 SIGINT/SIGTERM。
- 将重试逻辑封装进函数,每次循环开头检查
stop_event.is_set() - 主流程中调用
stop_event.set()即可立即退出所有重试线程 - 对长任务,每完成一个 chunk 下载就检查一次事件状态,避免卡在阻塞 I/O 中无法退出
最易被忽略的是:重连过程中若发生证书变更、代理配置更新、DNS 缓存过期,旧 session 可能持续失败。需要设计 session 重建触发点,而不是复用同一个 requests.Session() 对象到底。

















