SSE 协议
设置 stream=true 后,响应使用 text/event-stream。每个事件以 data: 开头,结束标记为 data: [DONE]。
无缓冲 curlbash
curl --no-buffer "https://cloudnode.skin/v1/chat/completions" \
--request POST \
--header "Authorization: Bearer $MOFANG_API_KEY" \
--header "Content-Type: application/json" \
--data '{"model":"YOUR_MODEL_ALIAS","messages":[{"role":"user","content":"Hello"}],"stream":true,"stream_options":{"include_usage":true}}'取消与超时
为连接设置总超时。用户离开页面或任务取消时,应 abort 请求并 cancel reader,让 Gateway 尽快收到客户端断开。
- 首个下游字节发出后,平台不会切换到另一个 Channel
- 中途断流可能按已确认并已交付的 Token 结算为 PARTIAL
- 不要把半段响应与一次新请求的响应拼接
Node.js 超时与断开javascript
const controller = new AbortController();
const timeout = setTimeout(() => controller.abort(), 60_000);
let reader;
let response;
try {
response = await fetch("https://cloudnode.skin/v1/chat/completions", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.MOFANG_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
model: "YOUR_MODEL_ALIAS",
messages: [{ role: "user", content: "Hello" }],
stream: true,
stream_options: { include_usage: true },
}),
signal: controller.signal,
});
if (!response.ok || !response.body) throw new Error(await response.text());
reader = response.body.getReader();
const decoder = new TextDecoder();
while (true) {
const { done, value } = await reader.read();
if (done) break;
const text = decoder.decode(value, { stream: true });
process.stdout.write(text);
if (text.includes("data: [DONE]")) break;
}
} finally {
clearTimeout(timeout);
await reader?.cancel();
if (response?.body) await response.body.cancel();
}