ConnectionResetError是对方发送RST强制断连,socket已失效,盲目重试会立即再报错;须用Session+HTTPAdapter配置connect重试、启用TCP Keepalive保活,或对高防站换tls-client绕过TLS指纹检测。

ConnectionResetError 不是临时抖动,而是对端已发 RST 强制断连——此时 socket 句柄已失效,不能复用,也不能靠“重试”就解决。盲目重试只会立刻再抛一次错误。
为什么直接 try-except + 重试会失败
requests 或 urllib3 的连接池里可能还存着一个“看起来没关闭”的 socket,但系统 TCP 层早已断开。下次取出来 send(),内核直接返回 ConnectionResetError: [Errno 104] Connection reset by peer。
- 重试前没主动 close() 原连接 → 复用失效句柄
- 没清空连接池 → 下次 get() 还可能拿到坏连接
- 没区分错误类型 → 把服务端拒绝(如 WAF 主动 RST)当成可重试的网络抖动
requests 里用 HTTPAdapter 配置带状态码感知的重试
urllib3 的 Retry 能跳过连接层错误,只对特定 HTTP 状态码重试;对 ConnectionResetError 这类底层异常,它默认不重试(合理),但你可以让它在连接失败时重建连接。
- 必须用
Session+HTTPAdapter,不能对单次requests.get()加 retry -
total=3包含连接失败、读超时、状态码重试等所有失败次数 -
connect和read分开控制更准:connect=3, read=0表示只重试建连阶段 -
backoff_factor=0.3让重试间隔为 0.3s、0.6s、1.2s(避免雪崩)
from requests import Session
from requests.adapters import HTTPAdapter
from urllib3.util.retry import Retry
<p>session = Session()
retry = Retry(
connect=3,
read=0,
backoff_factor=0.3,
status_forcelist=[502, 503, 504],
)
adapter = HTTPAdapter(max_retries=retry)
session.mount("http://", adapter)
session.mount("https://", adapter)</p><h1>后续所有 session.get() 都自动重连建连失败</h1><p>response = session.get("<a href="https://www.php.cn/link/710ba53b0d353329706ee1bedf4b9b39">https://www.php.cn/link/710ba53b0d353329706ee1bedf4b9b39</a>", timeout=10)
自建 socket 时必须启用并调小 TCP Keepalive
Python socket 默认不开启 keepalive,操作系统默认 7200 秒才探测,远超服务端空闲超时(常见 60–300 秒)。不设就会在 send() 时突然收到 RST。
立即学习“Python免费学习笔记(深入)”;
-
setsockopt(..., socket.SO_KEEPALIVE, 1)必须在connect()之后、send()之前调 - Linux:用
TCP_KEEPIDLE/TCP_KEEPINTVL/TCP_KEEPCNT控制探测节奏 - Windows:需用
socket.ioctl(socket.SIO_KEEPALIVE_VALS, ...),不支持TCP_KEEPIDLE - Keepalive 只保活 TCP,WebSocket 还得自己发
ping/pong
爬虫场景下 ConnectionResetError(10054) 很可能是被 WAF 主动拦截
Cloudflare、阿里云 WAF、腾讯 EdgeOne 等会在 TLS 握手阶段就 RST,根本没走到 HTTP 层。这时候加 time.sleep()、换 User-Agent、甚至重试 10 次都没用。
- 错误发生在
connect()或 SSL handshake 阶段,不是请求发出后返回的 - requests 基于 OpenSSL,TLS 指纹(cipher list、ALPN、SNI 顺序)和浏览器差异大
- 真实解法是换底层:用
tls-client(Go 写的 TLS 实现)或curl-cffi(调用 libcurl + 浏览器引擎) - 必须保证 SNI 域名、DNS 解析 IP、Host header、TLS SNI 四者一致,否则高防直接断连
关键点容易被忽略:ConnectionResetError 的根源不在你的重试逻辑是否够多,而在于你有没有在连接建立后、业务使用前,确认它真的“还活着”。对 HTTP 客户端,要靠 Session 级重试机制重建连接;对原始 socket,要靠系统级 keepalive 探测;对高防站点,得先绕过 TLS 指纹识别——否则一切重连都是徒劳。


















