这是python旧版本(如3.6及更早)默认使用tls 1.0/1.1所致,主流服务已禁用这些协议,导致握手失败;根本解法是升级python至3.7+并确保openssl≥1.1.1。

为什么 requests 会报 ssl.SSLError: TLSV1_ALERT_PROTOCOL_VERSION
这是 Python 旧版本(尤其是 3.6 及更早)默认使用 TLS 1.0 或 1.1 的结果。主流服务(如 GitHub API、PyPI、AWS、Cloudflare 后端)已禁用这些低版本协议,握手直接失败。不是证书问题,也不是网络问题,纯粹是客户端协议协商能力不足。
升级 Python 是最稳妥的解法
Python 3.7+ 默认启用 TLS 1.2,3.8+ 默认支持 TLS 1.3。如果你还在用 3.6 或更早版本,pip install --upgrade python 不可行——必须重装解释器。
- 确认当前版本:
python --version - Mac 用户建议用
pyenv安装 3.9+:pyenv install 3.11.9 && pyenv global 3.11.9 - Windows 用户从 python.org 下载安装包,勾选 “Add Python to PATH”
- 注意:某些 Linux 发行版自带的系统 Python(如 CentOS 7 的 2.7.5 / 3.6.8)无法通过
apt upgrade升级到安全协议版本,必须编译或换源
临时绕过(仅限调试,禁止生产)
如果暂时无法升级 Python,且调用的是你可控的内部服务(比如自建的测试 API),可强制 requests 使用更高 TLS 版本。但注意:urllib3 底层依赖 ssl 模块,若 OpenSSL 库太老(如 1.0.1e),即使改代码也无效。
import ssl
from urllib3.util.ssl_ import create_urllib3_context
<h1>强制 urllib3 使用 TLS 1.2+</h1><p>class CustomHTTPSAdapter(requests.adapters.HTTPAdapter):
def init_poolmanager(self, *args, *<em>kwargs):
context = create_urllib3_context()
context.minimum_version = ssl.TLSVersion.TLSv1_2
kwargs['ssl_context'] = context
return super().init_poolmanager(</em>args, **kwargs)</p><p>session = requests.Session()
session.mount('https://', CustomHTTPSAdapter())
response = session.get('<a href="https://www.php.cn/link/e41bbd4af5da30044b88dc9ab711c5b2">https://www.php.cn/link/e41bbd4af5da30044b88dc9ab711c5b2</a>') # 这样才可能成功
</p>
- 该方法对 Python 3.6 + OpenSSL 1.1.1+ 有效;3.6 + OpenSSL 1.0.x 仍会失败
-
requests.packages.urllib3在较新版本中已被私有化,不要直接 monkey patch - 绝对不要在生产环境设置
verify=False或降级到ssl.PROTOCOL_TLSv1
检查并更新底层 OpenSSL
Python 的 SSL 能力取决于编译时链接的 OpenSSL 版本,而非系统命令行的 openssl version 输出。运行以下代码确认:
import ssl print(ssl.OPENSSL_VERSION) # 如 'OpenSSL 1.0.2k-fips' 就太旧了 print(ssl.HAS_TLSv1_2) # 应为 True print(ssl.HAS_TLSv1_3) # Python 3.7+ 且 OpenSSL ≥ 1.1.1 才为 True
- macOS 上 Homebrew 安装的 Python 通常自带新版 OpenSSL;系统自带 Python 则大概率绑着古董 OpenSSL
- Docker 用户应在
Dockerfile中显式安装新版 OpenSSL 并重新编译 Python,或直接用python:3.11-slim等官方镜像 - conda 环境可通过
conda update openssl更新,但需确保 Python 重建 SSL 模块(有时需重装python包)
真正卡住人的往往不是代码怎么写,而是没意识到 Python 解释器和它背后的 OpenSSL 是两个独立可变因素——升级 Python 版本只是第一步,还得看它实际加载的是哪套加密库。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











