【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 完整代码(复制即用)

python 复制代码
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

使用:

python 复制代码
# 在业务逻辑最顶部调用即可
monkey_patch()

3 逐段技巧拆解

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

4 何时删除?

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

5 延伸阅读


一句话总结

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

相关推荐
老詹图解IT5 分钟前
统信 UOS 登录界面转圈闪退/卡登录等常见原因及处理
linux·服务器·网络
la_vie_est_belle6 分钟前
纯Python游戏引擎 新增可视化一键打包功能
python·游戏开发·pygame·python开发·pygame studio
最贪吃的虎8 分钟前
给 Agent 接入新模型的推理模式:从配置开关到协议适配
人工智能·python·langchain
轻颂呀12 分钟前
进程间关系和守护进程
linux·网络
熊猫_豆豆12 分钟前
仿真模拟两颗卫星的自主交会对接过程(Python版)
开发语言·python
小江的记录本29 分钟前
【MySQL】《MySQL日志面试背诵版+思维导图》(核心考点 + MySQL 8.0最新优化)
java·数据库·后端·python·sql·mysql·面试
西洼工作室29 分钟前
Python邮箱工具类封装:高效邮件发送与管理
python·全栈
子午35 分钟前
基于YOLO的水稻害虫检测系统~Python+yolov8算法+深度学习+人工智能+模型训练
人工智能·python·yolo
QH1392923188036 分钟前
R&S®SMBV100B 矢量信号发生器 5G/Wi-Fi/GNSS 主力源
网络·科技·嵌入式硬件·集成测试·信息与通信
我命由我1234537 分钟前
Android Framework P2 - 开机启动 Zygote 进程、Zygote 的预加载机制
android·java·开发语言·python·java-ee·intellij-idea·zygote