跳到主要内容
ecdsa.com
Python ssl module (OpenSSL)Python cryptography 库

错误信息

[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 无法得知对端为何断开;原因在服务器上,或者在中间的代理或防火墙上。

原因

修复方法

  1. 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. 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. 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/")

相关错误

浏览完整的签名错误库