使用 Fetch + Streams 处理流式响应(Streaming Response)
使用 Fetch + Streams 处理流式响应(Streaming Response)
📌 一、用途说明
该代码用于从一个支持流式响应的服务器接口读取数据,一般用于:
- 与 OpenAI、ChatGPT 等模型的实时对话接口
- 音视频分片下载
- Server-Sent Events(SSE)或其他长连接传输
- 后端支持
chunked transfer encoding
的接口
🧩 二、完整代码
try {const response = await fetch("http://127.0.0.1:8000/AI/chat", {method: "POST",headers: {"Content-Type": "application/json"},body: JSON.stringify({ query: content })});const reader = response.body.getReader();const decoder = new TextDecoder();let done = false;let result = '';while (!done) {const { value, done: doneReading } = await reader.read();done = doneReading;let resultString = decoder.decode(value, { stream: true });result += resultString;console.log(resultString);}
} catch (error) {console.error("请求失败:", error);
}
🔍 三、逐项详解
行 | 代码片段 | 说明 |
---|---|---|
fetch(...) | 使用 Fetch API 发起 POST 请求 | |
headers: { "Content-Type": "application/json" } | 声明请求体是 JSON 类型 | |
JSON.stringify({ query: content }) | 将 JavaScript 对象转换为 JSON 字符串 | |
response.body.getReader() | 获取 ReadableStream 的读取器(Reader) | |
TextDecoder() | 创建一个用于将字节流解码为文本的对象 | |
reader.read() | 异步读取下一段数据,返回 { value, done } | |
decoder.decode(value, { stream: true }) | 解码字节为字符串,stream 选项表示多段解码 | |
result += resultString | 可选,用于累积最终结果 | |
console.log(resultString) | 打印每次读取的结果,模拟实时输出 |
🔁 四、类似用法对比
✅ 示例 1:读取流式 JSON 响应
const reader = response.body.getReader();
const decoder = new TextDecoder();
let buffer = "";while (true) {const { value, done } = await reader.read();if (done) break;buffer += decoder.decode(value, { stream: true });try {const json = JSON.parse(buffer);console.log("解析成功:", json);break;} catch (e) {// 继续读取直到 JSON 完整}
}
✅ 示例 2:处理 SSE(Server-Sent Events)事件流
const response = await fetch("/sse");
const reader = response.body.getReader();
const decoder = new TextDecoder();
let partial = "";while (true) {const { value, done } = await reader.read();if (done) break;partial += decoder.decode(value, { stream: true });const events = partial.split("\n\n");for (let i = 0; i < events.length - 1; i++) {const event = events[i];if (event.startsWith("data:")) {const data = event.replace("data: ", "");console.log("收到事件:", data);}}partial = events[events.length - 1];
}
✅ 示例 3:Blob/视频流读取
const response = await fetch("/video");
const reader = response.body.getReader();
let chunks = [];while (true) {const { value, done } = await reader.read();if (done) break;chunks.push(value);
}const blob = new Blob(chunks, { type: "video/mp4" });
document.querySelector("video").src = URL.createObjectURL(blob);
🧠 五、补充知识:TextDecoder 的作用
TextDecoder
是浏览器提供的用于解码 Uint8Array
字节为字符串的 API。
常用方法:
const decoder = new TextDecoder("utf-8");
decoder.decode(Uint8Array, { stream: true });
{ stream: true }
:允许将未完成的字节块保留到下一次调用,防止字符乱码或丢失。
🧰 六、其他工具库推荐
react-streaming
readable-stream
(Node.js)eventsource-parser
(处理 SSE)
✅ 七、参考文档
- MDN:
fetch
- MDN:
ReadableStream
- MDN:
TextDecoder