在Python网络请求开发中,使用requests库调用HTTPS接口时,SSL验证失败 是高频棘手问题。无论是爬虫采集、接口调试还是生产环境调用,均可能因证书信任、协议兼容、环境配置等问题触发验证报错,导致请求中断。这类问题看似复杂,实则根源可归纳为证书有效性、本地信任机制、协议适配三类场景。当使用requests库遇到SSL验证失败时,可以通过以下几种方式解决。
一. 解决办法
1. 临时禁用SSL验证(不推荐用于生产环境)
python
import requests
# 方法1:全局禁用
response = requests.get('https://example.com', verify=False)
# 方法2:对于特定请求禁用
response = requests.get('https://example.com', verify=False)
# 方法3:使用上下文管理器临时禁用
import urllib3
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) # 禁用警告
response = requests.get('https://example.com', verify=False)
2. 指定自定义CA证书
python
import requests
# 指定证书文件路径
response = requests.get('https://example.com',
verify='/path/to/certificate.pem')
# 指定证书目录
response = requests.get('https://example.com',
verify='/path/to/certs/')
# 使用系统证书(Windows/Mac/Linux)
response = requests.get('https://example.com',
verify=True) # 默认就是True
3. 安装并更新证书(推荐)
方法1:使用certifi库(推荐)
python
import requests
import certifi
# 使用certifi提供的证书
response = requests.get('https://example.com',
verify=certifi.where())
# 更新certifi证书
# 在命令行执行:
# pip install --upgrade certifi
方法2:手动安装证书
bash
# Ubuntu/Debian
sudo apt-get install ca-certificates
# CentOS/RHEL
sudo yum install ca-certificates
# macOS
# 证书通常已经内置,可以通过钥匙串访问管理
# Windows
# 从受信任的CA机构下载证书
4. 设置环境变量(开发环境)
python
import os
os.environ['REQUESTS_CA_BUNDLE'] = '/path/to/certificate.pem'
os.environ['SSL_CERT_FILE'] = '/path/to/certificate.pem'
# 或者在运行前设置环境变量
# export REQUESTS_CA_BUNDLE=/path/to/certificate.pem
5. 使用自定义SSL适配器(高级)
python
import requests
from requests.adapters import HTTPAdapter
from urllib3.poolmanager import PoolManager
import ssl
class SSLAdapter(HTTPAdapter):
def init_poolmanager(self, *args, **kwargs):
ctx = ssl.create_default_context()
ctx.check_hostname = False
ctx.verify_mode = ssl.CERT_NONE
kwargs['ssl_context'] = ctx
return super().init_poolmanager(*args, **kwargs)
session = requests.Session()
session.mount('https://', SSLAdapter())
response = session.get('https://example.com')
二. 常见问题解决方案
问题1:自签名证书
python
# 导出服务器的证书
# openssl s_client -connect example.com:443 -showcerts </dev/null 2>/dev/null | openssl x509 -outform PEM > mycert.pem
# 然后使用该证书
response = requests.get('https://example.com',
verify='mycert.pem')
问题2:证书路径问题
python
import os
# 查找证书路径
print(requests.certs.where()) # requests使用的证书路径
print(certifi.where()) # certifi提供的证书路径
# 设置requests使用系统证书
if os.name == 'nt': # Windows
cert_path = 'C:/Python39/Lib/site-packages/certifi/cacert.pem'
else: # Linux/Mac
cert_path = '/usr/local/lib/python3.9/site-packages/certifi/cacert.pem'
response = requests.get('https://example.com', verify=cert_path)
问题3:代理环境下的SSL问题
python
import requests
proxies = {
'http': 'http://proxy.example.com:8080',
'https': 'http://proxy.example.com:8080',
}
# 可能需要同时禁用SSL验证
response = requests.get('https://example.com',
proxies=proxies,
verify=False)
三. 最佳实践代码示例
python
import requests
import certifi
from requests.adapters import HTTPAdapter
from urllib3.util.retry import Retry
import urllib3
import warnings
# 禁用SSL警告
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
warnings.filterwarnings('ignore', message='Unverified HTTPS request')
def create_secure_session():
"""创建安全的requests会话"""
session = requests.Session()
# 设置重试策略
retry_strategy = Retry(
total=3,
backoff_factor=1,
status_forcelist=[429, 500, 502, 503, 504],
)
adapter = HTTPAdapter(max_retries=retry_strategy)
session.mount("https://", adapter)
session.mount("http://", adapter)
return session
def make_request(url, use_ssl=True):
"""安全的请求函数"""
session = create_secure_session()
try:
if use_ssl:
# 使用certifi证书
response = session.get(url, verify=certifi.where(), timeout=30)
else:
# 开发环境禁用SSL
response = session.get(url, verify=False, timeout=30)
response.raise_for_status() # 检查HTTP错误
return response
except requests.exceptions.SSLError as e:
print(f"SSL错误: {e}")
# 尝试使用系统证书
try:
response = session.get(url, verify=True, timeout=30)
return response
except:
raise
except requests.exceptions.RequestException as e:
print(f"请求错误: {e}")
raise
# 使用示例
try:
response = make_request('https://example.com')
print(response.text)
except Exception as e:
print(f"请求失败: {e}")
四. 检测和诊断SSL问题
python
import ssl
import requests
def check_ssl_info(url):
"""检查SSL证书信息"""
try:
response = requests.get(url, timeout=10)
print(f"URL: {url}")
print(f"状态码: {response.status_code}")
print(f"使用的证书: {response.raw.connection.sock.getpeercert()}")
except requests.exceptions.SSLError as e:
print(f"SSL错误详情: {e}")
print(f"错误类型: {type(e).__name__}")
except Exception as e:
print(f"其他错误: {e}")
# 检查requests使用的证书库
print(f"requests证书路径: {requests.certs.where()}")
print(f"OpenSSL版本: {ssl.OPENSSL_VERSION}")
# 检查特定网站的SSL
check_ssl_info('https://www.google.com')
注意事项:
- 生产环境不要 使用
verify=False,这会存在安全风险 - 开发/测试环境可以临时禁用SSL验证
- 建议使用
certifi库来管理证书 - 定期更新证书:
pip install --upgrade certifi
总结
在实际开发中,建议先排查证书有效性与本地信任配置,再优化协议适配,既能高效解决问题,又能兼顾系统安全性与稳定性。