Python2.7.5 requests发HTTPS请求报TLSV1_ALERT_INTERNAL_ERROR缺失SNI排查
排查Python服务调用requests时SNI未填充的步骤
首先明确前提:Python 2.7.9以下版本的原生ssl模块不支持SNI,requests库要实现SNI填充,必须额外安装pyOpenSSL、ndg-httpsclient、pyasn1三个依赖包,且依赖版本需要和requests版本匹配。服务和命令行表现不一致,核心原因是二者的运行环境存在差异,可按以下步骤排查:
- 检查两个场景的Python执行环境是否一致
分别在服务代码中、Python命令行中执行以下代码,对比输出是否完全相同:
如果服务运行时提示缺少上述三个SNI依赖,直接安装对应版本即可解决问题。import sys, requests, urllib3, ssl print(sys.executable) # 确认Python执行文件路径,排查是否用了不同的虚拟环境 print(sys.path) # 确认模块加载路径,排查是否加载了不同路径下的依赖库 print(requests.__version__, urllib3.__version__) # 确认requests、urllib3版本 print(ssl.OPENSSL_VERSION) # 确认底层openssl版本 # 检查SNI依赖是否已加载 try: import OpenSSL, ndg.httpsclient, pyasn1 print("SNI依赖已安装") except ImportError as e: print("缺少SNI依赖:", e) - 检查服务代码是否修改了requests默认SSL配置
排查全局代码中是否存在以下操作:- 自定义了
HTTPAdapter替换了requests默认的SSL处理逻辑,未携带SNI参数 - 手动修改了urllib3的SNI开关,例如配置了
urllib3.util.ssl_.DEFAULT_SNI_SUPPORT = False - 请求的目标URL在代码运行时被替换为了IP地址(SNI只能填写域名,IP请求不会携带SNI字段)
- 自定义了
- 检查运行身份的权限/包路径差异
如果服务是以systemd、supervisor托管运行,通常会使用指定用户(如root、www-data)启动,不同用户的全局pip包路径、家目录下的site-packages路径不同,可能出现命令行执行的普通用户已安装SNI依赖,但服务运行的用户未安装的情况,可切换到服务对应的运行用户执行命令行测试验证。 - 强制注入SNI验证问题根因
可在服务的请求代码中添加自定义SNI Adapter,强制指定SNI字段,验证是否能解决问题:
若添加后请求正常,可100%确认问题为服务运行环境默认未加载SNI支持,回到前序步骤排查依赖即可。import requests from requests.adapters import HTTPAdapter from urllib3.poolmanager import PoolManager from urlparse import urlparse class ForceSNIAdapter(HTTPAdapter): def init_poolmanager(self, connections, maxsize, block=False, **pool_kwargs): parsed_url = urlparse(registration_url) self.poolmanager = PoolManager( num_pools=connections, maxsize=maxsize, block=block, server_hostname=parsed_url.hostname ) session = requests.Session() session.mount("https://", ForceSNIAdapter()) resp = session.post(registration_url, data=json.dumps(request_payload), headers=headers)
内容的提问来源于stack exchange,提问作者user198234
相关产品推荐
相关产品推荐

