解决Django调用外部API时出现的SSLError问题
解决Django站点调用外部API出现"No cipher can be selected" SSL错误
核心原因
这个错误源于生产服务器与API服务器的SSL加密套件无法匹配——生产服务器支持的加密套件列表中,没有API服务器认可的选项,而本地环境的SSL配置包含兼容套件,因此能正常运行。
排查与解决步骤
1. 核对双方支持的SSL加密套件
- 在生产服务器执行以下命令,查看本地支持的所有加密套件:
openssl ciphers -v - 查看API服务器支持的加密套件,执行:
从输出中找到openssl s_client -connect <你的API_HOST>:443Cipher字段对应的内容,对比本地列表是否有匹配项。
2. 在requests请求中强制指定兼容的加密套件
如果生产服务器无法快速更新SSL配置,可以在代码中自定义SSL上下文,指定API服务器支持的加密套件:
import requests import ssl from requests.adapters import HTTPAdapter from urllib3.poolmanager import PoolManager from django.core.exceptions import EmptyResultSet import json class CipherAdapter(HTTPAdapter): def init_poolmanager(self, *args, **kwargs): ctx = ssl.create_default_context() # 替换为API服务器支持的加密套件,可从openssl s_client结果中选取 ctx.set_ciphers('ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256') kwargs['ssl_context'] = ctx return super().init_poolmanager(*args, **kwargs) # 使用自定义Adapter发送请求 session = requests.Session() session.mount('https://', CipherAdapter()) try: r = session.post(url, data=json.dumps(dados), headers=headers, timeout=30) except requests.exceptions.Timeout: raise EmptyResultSet(f'Erro API TIMEOUT') if r.status_code == requests.codes.ok: search = r.json() else: search = []
3. 检查依赖库版本兼容性
当前使用的requests 2.28.1和urllib3 1.26.11可能存在SSL相关的已知问题,尝试升级到稳定版:
pip install --upgrade requests==2.31.0 urllib3==2.0.7
升级前务必在测试环境验证,避免影响现有功能。
4. 调整生产服务器的系统SSL配置
检查Linux服务器的/etc/ssl/openssl.cnf文件,找到CipherSuite配置项,确保包含API服务器支持的加密套件。修改后重启Django运行的服务(如uWSGI、Gunicorn)使配置生效。
内容的提问来源于stack exchange,提问作者Lucas Nascimento
相关产品推荐
相关产品推荐

