前言:
一个通过 Cloudflare Tunnel 对外提供的 New API 服务上出现的403:Cloudflare AI Bot 误拦截问题。可以说说你的故事:阻碍、努力、结果成果,意外与转折。
📝 OpenAI Python SDK 请求 API 返回 403:Cloudflare AI Bot 误拦截问题排查笔记
一、问题背景
本次问题出现在一个通过 Cloudflare Tunnel 对外提供的 New API 服务上。
服务整体架构如下:
其中:
s.in是主域名;
api.s.in是s.in的子域名,专门用于提供 API 服务;
- Cloudflare 负责域名解析、CDN/安全防护以及 Tunnel;
- New API 运行在服务器 Docker 容器中;
- New API 对外提供 OpenAI-compatible API;
- Python 程序通过 OpenAI Python SDK 调用
/v1/chat/completions。
服务器上的 Docker 容器大致为:
New API 容器将宿主机的
3002 端口映射到容器的 3000 端口:因此,从服务器本机访问时可以直接使用:
而外部客户端则通过:
访问。
二、最初的错误现象
最开始使用 OpenAI Python SDK 请求:
最初遇到过:
后续在调整访问地址之后,错误变成了:
进一步捕获异常,可以看到:
这里有一个很重要的排查思路:
Connection error 和 403 是两个完全不同的方向。
Connection error 通常意味着请求没有正常建立或完成连接,例如:- DNS;
- TCP;
- TLS/HTTPS;
- 代理;
- 网络连通性。
而
403 Forbidden 说明请求已经到达了某个 HTTP 服务,并且这个服务明确拒绝了请求。因此,出现 403 之后,排查重点就应该从“Python 网络是不是有问题”,逐渐转向:
三、首先确认 API 服务本身是否正常
第一步不能直接怀疑 OpenAI SDK。
因为整个系统实际上存在很多层:
任何一层都可能返回错误。
因此首先使用最简单的 HTTP 客户端进行测试。
例如使用 curl:
结果正常返回模型回答,并且 HTTP 状态为成功。
这一步非常重要。
它说明至少下面这些东西基本正常:
也就是说,不能简单认为:
“API 服务坏了,所以 Python 调用失败。”
实际上 API 服务本身是可以正常处理请求的。
四、进一步测试 /v1/models
随后测试:
也可以正常访问。
这进一步证明:
- 域名解析正常;
- HTTPS 正常;
- Cloudflare Tunnel 正常;
- New API 正常;
- API Key 基本正常;
- API 路径正常。
不过这里仍然不能完全排除安全规则。
因为
/v1/models 和 /v1/chat/completions 是两个不同的 HTTP 请求,Cloudflare 或其他安全组件完全可能对它们采取不同的处理方式。因此不能因为:
就直接得出:
五、用 Python 的普通 HTTP 库进行对照实验
接下来使用 Python 的
httpx,而不是 OpenAI SDK:结果:
并且返回了正常的模型响应。
响应头中出现了:
这里出现了一个非常有价值的信息:
说明请求确实经过了 Cloudflare。
同时:
这些 New API 相关的响应头也出现了。
因此可以判断:
这进一步证明 Cloudflare Tunnel 和 New API 本身没有问题。
六、关键对照:为什么 OpenAI SDK 仍然 403?
到这里,问题范围已经明显缩小。
测试结果形成了一个非常有价值的对照表:
请求方式 | 结果 | |
curl | /v1/chat/completions | 200 |
httpx | /v1/chat/completions | 200 |
OpenAI Python SDK | /v1/chat/completions | 403 |
OpenAI SDK + 其他 base_url | 同类接口 | 正常 |
这个时候就应该意识到:
问题很可能不是 URL、API Key、模型或者 New API,而是 OpenAI SDK 发出的 HTTP 请求具有某些特殊特征。
尤其是:
这是排查代理、WAF、Bot 防护时非常典型的现象。
七、进一步排除系统代理
由于 Python 的
httpx、requests 等库可能读取系统中的代理环境变量,因此又使用:关闭环境代理的影响。
例如:
结果仍然是:
所以:
基本可以排除。
此时问题进一步缩小为:
八、真正关键的线索:User-Agent
OpenAI Python SDK 的请求具有自己的 User-Agent。
其中一个重要特征是:
因此尝试使用普通
httpx 模拟 OpenAI SDK 的请求特征,例如:结果变成:
响应:
这一步非常关键。
因为现在已经不是:
而是:
这说明真正触发拦截的很可能就是 Cloudflare 对请求自动程序特征的判断。
九、查看 403 响应,确定到底是谁拦截
这时候继续查看 403 的响应头:
响应内容:
与此同时,失败请求中没有看到成功请求中的:
这意味着一个非常重要的事实:
这个 403 请求很可能根本没有到达 New API。
如果 New API 返回错误,通常应该能看到 New API 相关的响应特征。
因此请求链路应该变成:
而成功请求则是:
至此,New API 基本可以从故障源中排除。
十、最终通过 Cloudflare Security Events 找到根因
最后在 Cloudflare 的 Security Events 中,根据时间以及
cf-ray 查询这次失败请求。对应事件显示:
其中最关键的是:
说明确实执行了拦截。
然后:
说明拦截来自 Cloudflare 管理的安全规则。
最重要的是:
以及:
到这里,整个问题就完全闭环了。
十一、问题的本质
Cloudflare 的 AI Bot 防护原本是为了防止 AI 爬虫抓取网站内容。
例如一个普通网站:
网站管理员可能希望 Cloudflare 阻止这类 AI crawler。
但是本次服务不是普通网站,而是:
客户端本身就是一个程序,而且 OpenAI Python SDK 的 User-Agent 是:
于是 Cloudflare 的 Bot 防护在这个场景下进行了错误判断:
所以这不是:
Python 是恶意程序。
也不是:
OpenAI SDK 有问题。
更准确的描述是:
Cloudflare 的 AI Bot 防护将正常的 OpenAI Python SDK API 客户端请求识别成了需要阻止的 AI 自动程序,产生了误拦截。
十二、为什么 curl 可以正常,而 OpenAI SDK 不行?
这个现象现在也很好解释。
curl 通常使用类似:
而 OpenAI Python SDK 使用:
Cloudflare 的 Bot 防护能够看到 HTTP 请求中的这些特征。
因此:
而:
这也解释了为什么最开始看起来像是:
“curl 明明可以,为什么 Python 不行?”
实际上两者访问的是同一个 API,区别只是请求本身携带的特征不同。
十三、最终解决方法
解决问题的核心不是修改 New API,也不是换模型,更不是重新生成 API Key。
而是调整 Cloudflare 对 AI 自动程序的访问策略。
本次使用的是 Cloudflare 新的 AI 爬网程序访问权限设置。
调整之后:
调整完成后,原来的 Python SDK 代码恢复正常:
能够正常返回模型结果。
十四、这里有一个容易产生误解的地方:api.s.in 并不是因为名字里有 api 才被拦截
api.s.in 是 s.in 的一个子域名:其中:
只是人为选择的一个子域名名称。
本次 Cloudflare 并不是因为:
中的
api 字符串而进行拦截。真正触发规则的是:
以及 Cloudflare 的:
因此完全没有必要为了这个问题把:
改成:
或者:
域名本身没有问题。
十五、以后遇到类似问题应该怎么排查
这次问题最值得保留下来的,其实不是具体某一个 Cloudflare 开关,而是排查方法。
当出现:
不要第一时间修改代码或者怀疑 API Key。
首先建立一个最小化的对照测试:
分别访问同一个:
例如:
这时就应该高度怀疑:
而不是继续检查模型参数。
然后查看 403 的响应头。
如果出现:
并且响应内容是:
就应该进一步去 Cloudflare Security Events 查询对应的
cf-ray。尤其关注:
这几个字段。
本次真正决定问题方向的就是:
看到这种信息后,就不应该继续在 New API 内部排查。
十六、一个可以长期使用的故障排查思路
以后遇到类似的 API 请求异常,可以按照下面的顺序处理:
如果:
这是一个非常强的信号:
先比较请求,不要急着改服务端业务代码。
如果:
那么更应该怀疑:
如果:
那说明整个链路基本没有问题。
十七、本次问题最终结论
本次故障最终可以浓缩成一句话:
New API、模型、API Key、Cloudflare Tunnel 和域名本身均正常;真正的问题是 Cloudflare 的 Managed Firewall 中Manage AI bots规则,将 OpenAI Python SDK 的User-Agent: OpenAI/Python误识别为需要阻止的 AI 自动程序,因此在请求到达 New API 之前直接返回了 403。调整 Cloudflare 的 AI 爬网程序访问策略后,OpenAI Python SDK 恢复正常。
完整请求链路可以最终总结为:
这类问题的核心经验是:
看到 403 时,首先要确定“是谁返回的 403”,再判断“为什么返回 403”。
尤其是在:
这种多层架构中,请求甚至可能还没有到达你的 API 服务,就已经在前面的安全层被拦截了。
本次通过
cf-ray、Security Events、source: firewallManaged、ref: ai-bots-block 和 userAgent: OpenAI/Python 最终定位到了具体规则,这比单纯修改 Python 代码更重要。以后遇到类似问题,应优先采用“多客户端对照 + HTTP 状态码 + 响应来源 + CDN/WAF 日志”的方式逐层缩小范围。有关NEW API安装或者使用上的问题,欢迎您在底部评论区留言,一起交流~
- Author:迷途
- URL:http://blog.ortech.nyc.mn/%E6%8A%80%E6%9C%AF%E5%88%86%E4%BA%AB/openai403problem
- Copyright:All articles in this blog, except for special statements, adopt BY-NC-SA agreement. Please indicate the source!
Relate Posts






