使用httpx请求HTTPS API遇SSL证书验证失败,requests却正常
问题分析与解决方法
一、httpx与requests的SSL验证差异
- 主机名校验严格度不同:requests和httpx均基于Python的ssl模块实现证书验证,但httpx的校验逻辑更严格。当证书的SAN(Subject Alternative Name)字段不包含请求主机名,或CN(Common Name)与主机名不匹配时,httpx会直接抛出
SSLCertVerificationError;而requests会兼容部分旧证书配置,比如SAN缺失但CN匹配的情况,仍能通过验证。 - 根证书加载逻辑差异:macOS环境下,requests会自动读取系统Keychain中的根证书;httpx在部分场景下可能无法正确加载系统根证书,导致合法证书也无法通过校验。
二、解决方法
针对你的异步场景,可采用以下方案:
1. 确认base_url主机名与证书完全匹配
检查base_url中的主机名(如https://api.example.com)是否和证书颁发的主机名一致,注意不要包含多余的端口号(除非证书明确包含带端口的主机名),避免拼写错误。
2. 手动指定系统根证书路径
macOS的系统根证书通常存放在/etc/ssl/cert.pem或/usr/local/etc/openssl/cert.pem,创建httpx客户端时指定该路径即可:
import httpx import json creds = {'username': '123', 'password': '456'} headers = {'Content-Type': 'application/json'} client = httpx.Client(base_url=base_url, headers=headers, verify='/etc/ssl/cert.pem') # 异步客户端写法 # async with httpx.AsyncClient(base_url=base_url, headers=headers, verify='/etc/ssl/cert.pem') as client: params = json.dumps(creds) resp = client.post('/login', data=params)
3. 临时关闭SSL验证(仅测试环境使用)
若为测试环境且信任目标API,可临时跳过SSL验证,生产环境绝对禁止:
client = httpx.Client(base_url=base_url, headers=headers, verify=False) # 异步客户端写法 # async with httpx.AsyncClient(base_url=base_url, headers=headers, verify=False) as client:
4. 将自定义证书加入系统信任列表
若目标API使用自签名或内部CA证书,可将证书添加到macOS Keychain:
- 打开Keychain Access应用
- 将证书文件拖入「System」或「Login」钥匙串
- 双击证书,在「信任」选项卡设置「使用此证书时」为「始终信任」
之后httpx即可正常识别该证书。
三、优化提示
你的代码中手动序列化JSON并传入data参数,其实httpx支持直接使用json参数自动处理序列化和Content-Type头,代码更简洁:
resp = client.post('/login', json=creds)
内容的提问来源于stack exchange,提问作者c0d1ng
相关产品推荐
相关产品推荐

