use-case

SSE 流式响应与 WebSocket 实时连接

直接答案SSE 是单次 HTTP 响应的事件流,WebSocket 是双向长连接;客户端必须按协议事件判断完成,不能把 HTTP 200 或连接关闭当成业务成功。

更新 · 审核信息

小白:先跑通一个无缓冲流

curl -N 会关闭客户端输出缓冲。下面以 Chat Completions 为例;模型必须在模型广场中支持该端点。

curl -N "$BASE_URL/v1/chat/completions"   -H "Authorization: Bearer $API_KEY"   -H "Content-Type: application/json"   -d '{"model":"<MODEL_ID>","stream":true,"messages":[{"role":"user","content":"用三句话解释 SSE"}]}'

看到第一段文本不等于请求完成。Chat 常见完成标志、Responses 类型化事件、Claude content block 事件和 Gemini SSE 都不同,客户端应为目标协议使用独立解析器。

正确解析 SSE

按空行切分事件,合并连续 data: 行,忽略注释心跳,再根据 event 或 payload 内的类型分派。不要按 TCP 数据包、单次 read() 或换行直接解析 JSON;一个 JSON 可能跨读取块,一个读取块也可能包含多个事件。限制单事件大小并持续消费,避免慢客户端把上游连接和内存拖住。

完成、错误和取消

只有收到协议定义的完成事件并完成所有工具调用或媒体片段,才把业务状态记为成功。HTTP 200 之后仍可能出现流内错误。客户端主动取消时要关闭响应体并传播 Context/AbortSignal;服务端是否已经生成或计费需通过日志与 usage 核对,不能假定断线必然免费。

代理与部署检查

反向代理应关闭不必要的响应缓冲和压缩聚合,设置足够的空闲超时,并允许事件及时 flush。监控 DNS、连接、首字节、首 token、完整响应、断线位置和完成事件。浏览器跨域时还要核对 CORS;企业代理可能截断长连接。

WebSocket 不是 SSE

/v1/realtime 是双向 WebSocket。它具有会话状态、并发输入、服务端事件、音频帧和关闭码,不能使用 EventSource。为每个连接设置认证、最大消息、心跳、空闲时间、总时长和背压;高风险工具调用应在服务端再次授权。

专家恢复边界

为每次生成分配业务幂等键并记录 Request-ID、模型、事件序号和已提交工具操作。文本展示可以容忍部分结果,但数据库写入、付款或外部消息必须通过工具层幂等。若协议没有恢复游标,断线后应把结果标为“未知”,由业务决定重新生成、人工确认或放弃,而不是静默重试。

适用场景

  • 聊天逐字输出与工具事件
  • 实时语音、取消与长响应

API 协议

  • /v1/chat/completions
  • /v1/responses
  • /v1/messages
  • /v1/realtime

FAQ

为什么 HTTP 200 后仍可能失败?

流式响应会先发送响应头,后续事件仍可能携带错误。必须解析每个事件并看到协议定义的完成标志。

可以把 SSE 当作一行一个 JSON 吗?

不能直接假设。SSE 有 event、data、空行分隔和注释;不同协议的事件类型、完成标志和 payload 结构也不同。

断线后应该自动续传吗?

只有协议明确提供游标或可恢复语义时才续传。普通生成断线后结果可能未知,盲目重发可能重复工具调用或费用。

官方来源

  1. OpenAI Streaming Responses Official
  2. Claude Streaming Messages Official
  3. Gemini API Errors Official