错误信息
[SSL: UNEXPECTED_EOF_WHILE_READING] EOF occurred in violation of protocol
也可能输出为
- ssl.SSLEOFError: EOF occurred in violation of protocol
使用 OpenSSL 3 时,Python 显示原因代码“[SSL: UNEXPECTED_EOF_WHILE_READING]”;使用 OpenSSL 1.1.1 时,文本只有“EOF occurred in violation of protocol”。后面跟着源代码位置,例如“(_ssl.c:1082)”。
Python ssl module (OpenSSL) — ssl.SSLEOFError, SSL_R_UNEXPECTED_EOF_WHILE_READING
含义
在 Python 仍处于 TLS 握手(或正在读取数据)时,对端关闭了 TCP 连接,既没有发送 TLS 告警,也没有发送 close_notify。OpenSSL 把这种静默挂断视为违反协议。Python 无法得知对端为何断开;原因在服务器上,或者在中间的代理或防火墙上。
原因
服务器丢弃了它不接受的握手
常见当 ClientHello 缺少 SNI、没有提供可接受的版本或加密算法,或者名称未在服务器上配置时,一些服务器和负载均衡器会直接关闭连接,而不是发送告警。
代理、防火墙或 VPN 切断了连接
常见错误的代理设置(HTTPS_PROXY 指向 TLS 代理端口、没有为内部主机设置 NO_PROXY)、拦截目标地址的深度包检测,或者 VPN 客户端,常常会静默结束 TCP 连接。
限流或机器人防护
偶见高负载下的 API 和 CDN,或者不认可 Python TLS 指纹的反机器人系统,可能会重置连接,而不是返回 HTTP 错误。
服务器在响应中途关闭了连接
偶见如果错误是在读取响应时抛出的,说明服务器或代理在没有发送 close_notify 的情况下终止了连接,例如在超时或工作进程崩溃之后。
修复方法
- 1.
用 openssl s_client 复现握手
如果 s_client 也被断开连接,就改变 SNI 和 TLS 版本,看看服务器拒绝的是什么;如果 s_client 正常,就把它的设置与你的 Python 客户端对比(代理、SNI、版本)。
bash # Does a plain OpenSSL handshake work from the same machine? openssl s_client -connect api.example.com:443 -servername api.example.com -brief </dev/null # Without SNI, and pinned to TLS 1.2, to see what the server objects to openssl s_client -connect api.example.com:443 -noservername -brief </dev/null openssl s_client -connect api.example.com:443 -servername api.example.com -tls1_2 -brief </dev/null - 2.
检查代理环境变量
requests、urllib 和 pip 都会遵循 HTTPS_PROXY 和 NO_PROXY。修正代理 URL 的协议,并排除必须直连的内部主机。
bash env | grep -i -E '^(https?|no|all)_proxy=' # Proxy URLs should normally be http:// (CONNECT tunnel), and internal hosts listed in NO_PROXY export HTTPS_PROXY=http://proxy.example.net:3128 export NO_PROXY=localhost,127.0.0.1,.internal.example.com - 3.
原因是暂时性问题时重试
对于限流和不稳定的网络,带退避的重试能把偶发的重置变成较慢的成功;但它解决不了始终拒绝握手的服务器。
python import requests from requests.adapters import HTTPAdapter from urllib3.util.retry import Retry session = requests.Session() session.mount("https://", HTTPAdapter(max_retries=Retry(total=3, backoff_factor=1))) session.get("https://api.example.com/")
相关错误
[SSL: WRONG_VERSION_NUMBER] wrong version numberPython ssl module (OpenSSL)curl: (56) OpenSSL SSL_read: error:0A000126:SSL routines::unexpected eof while…curl (OpenSSL 3 backend)error:0A000126:SSL routines::unexpected eof while readingOpenSSL 3Client network socket disconnected before secure TLS connection was establishedNode.js tls / https / fetch