> 技术文档 > 【SSL证书校验问题】通过 monkey-patch 关掉 SSL 证书校验

【SSL证书校验问题】通过 monkey-patch 关掉 SSL 证书校验

标签:Python、SSL、monkey-patch、httpx、aiohttp、requests、OpenAI


1 为什么会有这篇文章?

在本地调试 OpenAI 代理、数据抓取、私有服务、访问外网 时,经常会碰到如下报错:

SSLCertVerificationError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed
raise SSLError(e, request=request)requests.exceptions.SSLError: HTTPSConnectionPool(host=\'api.openai.com\', port=443): Max retries exceeded with url: /v1/models (Caused by SSLError(SSLError(1, \'[SSL: WRONG_VERSION_NUMBER] wrong version number (_ssl.c:1017)\')))
File \".venv\\lib\\site-packages\\httpx\\_transports\\default.py\", line 118, in map_httpcore_exceptions | raise mapped_exc(message) from exc | httpx.ConnectError: All connection attempts failed
An error occurred: Expecting value: line 1 column 1 (char 0)An error occurred during the request: HTTPSConnectionPool(host=\'en.wikipedia.org\', port=443): Max retries exceeded with url: /w/api.php?list=search&srprop=&srlimit=1&limit=1&srsearch=langchain&format=json&action=query (Caused by ProxyError(\'Unable to connect to proxy\', SSLError(SSLEOFError(8, \'[SSL: UNEXPECTED_EOF_WHILE_READING] EOF occurred in violation of protocol (_ssl.c:1000)\'))))
 File \".venv\\lib\\site-packages\\requests\\adapters.py\", line 698, in send raise SSLError(e, request=request)requests.exceptions.SSLError: HTTPSConnectionPool(host=\'r.jina.ai\', port=443): Max retries exceeded with url: /https://baijiahao.baidu.com (Caused by SSLError(SSLCertVerificationError(1, \'[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: self signed certificate in certificate chain (_ssl.c:997)\')))

为了快速定位 “是不是证书问题” 而不是“逻辑问题”,我们需要临时零侵入地把所有 HTTP 客户端的 SSL 校验关掉。
把下面这段脚本调用后就能跑,调试结束直接删除,零副作用
或者为了临时绕过所有SSL证书验证,使代码逻辑跑通。


2 完整代码(复制即用)

def monkey_patch(): \"\"\" 通过关闭 SSL/TLS 证书验证,解决 ssl 验证引发的 443 超时问题 (注:临时调试使用,生产务必移除) \"\"\" import functools # 1) 全局标准库 SSL 上下文 try: import ssl # 全局取消证书验证 ssl._create_default_https_context = ssl._create_unverified_context except Exception: pass # 2) httpx 同步 & 异步 try: import httpx httpx.Client.__init__ = functools.partialmethod( httpx.Client.__init__, verify=False ) httpx.AsyncClient.__init__ = functools.partialmethod( httpx.AsyncClient.__init__, verify=False ) except Exception: pass # 3) OpenAI 私有 AsyncHttpxClientWrapper try: import openai._base_client as bc _old = bc.AsyncHttpxClientWrapper.__init__ def _new_init(self, *a, **k): k.setdefault(\"verify\", False) return _old(self, *a, **k) bc.AsyncHttpxClientWrapper.__init__ = _new_init except Exception: pass # 4) aiohttp try: import aiohttp aiohttp.TCPConnector.__init__ = functools.partialmethod( aiohttp.TCPConnector.__init__, verify_ssl=False ) except Exception: pass # 5) requests try: import requests from functools import wraps # 5-1) 修改 Session 实例默认属性 _orig_init = requests.Session.__init__ @wraps(_orig_init) def _patched_init(self): _orig_init(self) self.verify = False requests.Session.__init__ = _patched_init # 5-2) 快捷函数也兜底 for name in (\"get\", \"post\", \"put\", \"patch\", \"delete\", \"head\", \"options\"): _orig = getattr(requests, name) setattr( requests, name, (lambda _o: lambda *a, **k: _o(*a, **dict(k, verify=False)))(_orig), ) except Exception: pass

使用:

# 在业务逻辑最顶部调用即可monkey_patch()

3 逐段技巧拆解

位置 技巧 一句话解释 ssl._create_default_https_context = ... 全局钩子 把标准库 HTTPS 默认上下文换成“不校验”。 functools.partialmethod 一行改默认参数 不继承、不派生,直接把类方法的形参默认值改掉。 setdefault(\"verify\", False) 不覆盖显式传参 只在用户没传时兜底,传了 True 仍然生效。 @wraps 栈信息不丢失 调试时能看到原函数名,而不是 except Exception: 不吞系统信号 保留 KeyboardInterruptSystemExit,脚本可 Ctrl-C。

4 何时删除?

场景 建议 单测/本地调试 保留 代码评审 / 上线 必须删除 CI / Docker 用环境变量 SSL_NO_VERIFY=1 控制开关,而非硬编码

5 延伸阅读

  • Python 官方文档:ssl.create_default_context
  • httpx 文档:verify
  • requests 文档:Session.verify

一句话总结
通过侵入式修改,关掉全部 SSL 校验;调试完删掉,干净不留痕。