流式接口先返回 HTTP 200,只说明响应头到了。后面仍可能有错误事件,也可能套接字直接断开。2026-11-10 的文档把 OpenAI 的完成记成 response.completed,并把 Anthropic 在 200 之后的错误单独列出。没有事件时,先记下秒数。
OpenAI、Anthropic 和 Google 都没有把中国大陆写成这些 API 的无条件服务地。从名单外访问或向名单外提供访问,可能违反条款,账号或密钥可能被限制或停用。把断开的流续上,只处理已经开始的那一次响应,不改变地区资格。本文不写伪造证件、购买或借用账号、购买或共用密钥和支付卡。
先把 200 之后的结果分开
一个可单独引用的区分:HTTP 200 只说明流开始了;error 事件是对方写在流里的失败,套接字直接断开则是这条连接没有把后续事件送完。
| 你留下的记录 | 更像什么 | 下一步 |
|---|---|---|
| 没有状态码,一直等到超时或重置 | 路径没有到接口 | 按现象排查,不要记成 200 |
| 很快返回 401,或 Gemini 返回缺少身份的 403 | 认证 | 核对密钥,不要改出口 |
| OpenAI 的 403,正文是国家、地区或领土不支持 | 地区名单 | 停止把同一次请求反复重发 |
200 之后出现 error,或 Anthropic 的 overloaded_error | 流内的 API 错误 | 按该类型处理,保留请求 ID |
200 之后没有 error,也没有完成事件,套接字断开 | 连接中断 | 记下秒数,再看保活和传输 |
网页对话的 WebSocket 是另一条连接,见 ChatGPT 网页停住。SDK 的环境变量和读超时见 官方 SDK 怎么走代理。本文不重复那两个配置。
不带密钥时,当天三家各返回什么
起草环境不是大陆宽带。2026-11-10 用 curl 8.5.0 做了三次不带密钥的请求,只为看主机是否立刻给出 HTTP 错误。没有使用真实密钥,也没有发起真正的流式生成。
GET https://api.openai.com/v1/models 约 0.13 秒返回 HTTP 401,JSON 的 type 为 invalid_request_error,消息为 “Missing bearer authentication in header”,响应头有 x-request-id。一次观察到的值是 62ee4d9d-bc72-4ec4-b58c-b4e8346c9437。
POST https://api.anthropic.com/v1/messages,正文为 {},没有 x-api-key,也没有 anthropic-version,约 0.10 秒返回 HTTP 401。error.type 为 authentication_error,消息为 “x-api-key header is required”。响应头 x-should-retry 为 false,request-id 为 req_011CgtPSxxHd2LhiHcFgKLW1。这只说明这一次缺密钥的请求带了「不要重试」。不能推广到每一次 401。
GET https://generativelanguage.googleapis.com/v1beta/models 不带密钥,约 0.06 秒返回 HTTP 403,status 为 PERMISSION_DENIED,消息为 “Method doesn’t allow unregistered callers (callers without established identity). Please use API Key or other form of API consumer identity to call this API.”。这和「带了无效密钥」不是同一次实验。
三次都在一秒内给出 HTTP 正文。你自己的请求若完全没有状态码,先按 大陆代理连上后仍失败 查路径。401 与 OpenAI 403 的差别,账单部分见 国外 AI 的 API、订阅与支付排查。
OpenAI:完成事件和 error 是两行
Streaming API responses 在 2026-11-10 返回的 Markdown 响应头 last-modified 为 Tue, 10 Nov 2026 00:49:41 GMT。页面写明,默认是整段生成完再一次返回;stream=true 用服务器发送事件(SSE)。示例把完成写成 response.completed,把错误写成 type === "error"。同一页的 JavaScript 示例使用模型名 gpt-6-astra,后面的 Java 示例使用 gpt-5.5。本文没有调用这两个名字,也不把示例名字当成你账号里一定存在的模型。
页面没有写 ping 的间隔,也没有写大陆网络上套接字会在第几秒断开。因此:
- 看到
response.completed:这一次流按页面上的完成事件结束。 - 看到
error:记下message,不要把它记成「没有状态码的断开」。 - 两行都没有,连接已经断开:这是路径或客户端提前结束。记下从 200 到断开的秒数。
错误码 当天仍把 403 “Country, region, or territory not supported” 的原因写成从不支持的国家、地区或领土访问,解决办法只指向 地区说明。该说明页写明,名单外访问或提供访问,账号可能被封锁或暂停。当天 Markdown 名单里有 Taiwan,没有 China、Hong Kong、Macau。403 的这一行不是 SSE 中途断开。速率限制一节要求有 Retry-After 时至少等那么久;没有这个头时再增加间隔并加入少量随机延迟。同一页写到,Python 库可能在服务器延迟超过它支持的上限时停止自动重试。本文没有运行这个库,没有核对它的默认次数。
状态页有事故时,先看 status.openai.com,见 状态页正常,不等于路径通。
Anthropic:200 之后还有 error 和 ping
错误目录 写明:通过 SSE 接收流式响应时,错误可以发生在 API 已经返回 200 之后,这时不再走普通的 HTTP 错误处理,形状见流式文档的 Error events。目录里的 504 timeout_error 让长请求改用流式 Messages API。529 是 overloaded_error。官方 SDK 对连接错误、速率限制和 5xx 做指数退避,默认两次,并遵守 retry-after。这是目录里的句子。本文没有运行 SDK,不能证明你安装的那一版也是两次。
流式文档 把一条正常的流写成 message_start、内容块、message_delta,最后是 message_stop。它写明流里可以有任意多个 ping,示例为:
event: ping
data: {"type": "ping"}
页面没有给 ping 的间隔。没有等到 ping,不能换成一个固定秒数。
错误事件的例子是高负载时的 overloaded_error,对应非流式的 HTTP 529:
event: error
data: {"type": "error", "error": {"type": "overloaded_error", "message": "Overloaded"}}
收到这种事件,按过载或目录里的对应类型处理,并带上 request-id。没有 event: error、也没有 message_stop,则还没有收到对方写下的结束。先记秒数。
同一页的错误恢复按模型分成两段,都是把已经收到的文字续上去,而不是换一个账号:
- Claude 4.5 及更早:保存中断前的内容,把这部分作为新请求里的助手消息开头,再继续流式接收。
- Claude 4.6 及以后:同样先保存已收到的内容,但第二步改成用户消息,让模型从中断处继续。页面给的例句是 “Your previous response was interrupted and ended with [previous_response]. Continue from where you left off.”。
最佳实践写明,工具调用和 thinking 块不能部分恢复,只能从最近的文本块继续。这不能把 403 的权限或地区结果变成成功。目录里的 403 仍是 permission_error。地区资格另见支持地区页,不要用续写请求去试名单。
秒数稳定时,再看保活写在哪
断开若反复落在相近的秒数,且没有 error 事件,更接近路径把空闲连接回收了。sing-box 的非预发布标签在 2026-11-10 仍是 v1.14.4(2026-10-24T01:04:25Z)。拨号字段 写明 tcp_keep_alive 的默认初始周期是 5m,tcp_keep_alive_interval 的默认是 75s。启用 detour 后,同一组里的其他拨号字段会被忽略。保活因此要写在真正拨号的那条出站上。同一天的草稿 两层隧道时,AI 看见的是哪一跳 写了这个字段和路由器、电脑各开一条隧道时的对照;那一篇发布之前,链接打不开。
这 5 分钟是文档里的默认值,不是某家宽带的 NAT 时间。你记下的秒数若远短于 5 分钟,不要把它说成「已经证明就是 5 分钟保活」。UDP 上的空闲是另一条计时,见 仿 Chrome 会盖住更长的空闲超时 和 VPN 保活与掉线重连。
续写或 SDK 的自动重试会再发出一次请求。目录把自动重试的范围写成连接错误、速率限制和 5xx。国家不支持的 403 不在这句里面。第二次请求解释的是客户端又发了一次,不是账号被封的判定。
公开文件里的法律范围
2026-11-10 打开司法部国家行政法规库所载《计算机信息网络国际联网管理暂行规定》(1996 年 2 月 1 日国务院令第 195 号公布,1997 年 5 月 20 日第一次修订,2024 年 3 月 10 日第二次修订),页面为 LawID=1713。第六条写明,直接进行国际联网必须使用国家公用电信网提供的国际出入口信道,任何单位和个人不得自行建立或者使用其他信道进行国际联网。第十四条写明,违反第六条等规定的,由公安机关责令停止联网、给予警告,可以并处 15000 元以下的罚款。第十六条写明,与台湾、香港、澳门地区的联网参照执行。
这是公开条文的转述,不是对某一次 API 调用是否违法的判断,也不是法律意见。本文不写如何躲避检查。
一次断开留下的记录
留下七样东西:是哪一家的哪一个主机、HTTP 状态码、有没有 error 或 message_stop / response.completed、从 200 到断开的秒数、请求 ID、密钥是不是你自己的、有没有在 403 的国家错误上继续重试。起草环境的三次无密钥响应不能当作大陆宽带上的地区结论,也不能代替带密钥的流式生成。示例里的模型名以发布前再打开的流式页面为准。