javascript中用fetch api配合response.body(readablestream)处理服务端流数据,核心是调用getreader()逐块读取uint8array并实时处理,支持文本、ndjson、blob等场景,需注意浏览器兼容性和服务端分块配置。

JavaScript 中用 Ajax 处理服务端返回的流数据,核心是使用 fetch API 配合 Response.body(即 ReadableStream),而不是传统的 XMLHttpRequest 或 axios 默认的完整响应体解析方式。因为流式响应需要边接收、边处理,不能等全部数据到达后再解析。
用 fetch + ReadableStream 读取流数据
服务端以 Content-Type: application/octet-stream(或其他适合流的类型)返回分块数据时,fetch 的 response.body 是一个可读流,可通过 getReader() 获取阅读器逐块读取:
- 调用
response.body.getReader()得到ReadableStreamDefaultReader - 用
reader.read()循环读取{ done, value },其中value是Uint8Array - 对每块二进制数据做处理(如解码为文本、拼接、转 Blob、写入文件、渲染音视频等)
- 注意手动处理
done === true表示流结束
示例(读取纯文本流并实时打印):
fetch('/api/stream-log')
.then(response => {
const reader = response.body.getReader();
return new ReadableStream({
start(controller) {
function push() {
reader.read().then(({ done, value }) => {
if (done) {
controller.close();
return;
}
// 将 Uint8Array 转为字符串(假设 UTF-8)
const text = new TextDecoder().decode(value);
console.log(text);
controller.enqueue(value); // 可选:继续向下游传递
push();
});
}
push();
}
});
});
处理 JSON 流(如 NDJSON 或分块 JSON)
若服务端按行返回 JSON(如每行一个对象,即 NDJSON),需在流中按行切分,再逐行解析:
你接手一个需求时,是不是经常这样:"改一个小字段 → 结果把不相关的代码也改了"、"需求说得很模糊 → 做着做着发现跑偏了"、"数据库加个字段 → 上线才发现漏了数据兼容"、"做了个新功能 → 一个月后自己都忘了当时怎么设计的"、"写到一半被中断 → 再回来不知道从哪继续";这个 Skill 就是专门解决这些问题的。 它会自动探测你的项目环境(JDK、Spring Boot、ORM、数据库、前端框架),记在
- 用
TextDecoder将Uint8Array转为字符串 - 缓存未完成的行(如最后一块没换行符),拼接到下一块前再分割
- 对每行调用
JSON.parse(),捕获解析错误避免中断整个流
简单实现思路:
let buffer = '';
const decoder = new TextDecoder();
reader.read().then(function process({ done, value }) {
if (done && !buffer) return;
if (value) {
buffer += decoder.decode(value, { stream: true });
}
const lines = buffer.split('\n');
buffer = lines.pop(); // 保留不完整的最后一行
for (const line of lines) {
if (line.trim()) {
try {
const obj = JSON.parse(line);
console.log('Parsed:', obj);
} catch (e) {
console.warn('Invalid JSON line:', line);
}
}
}
if (!done) reader.read().then(process);
});
下载大文件或保存为 Blob
若流数据是图片、PDF、视频等二进制资源,可直接用 stream.pipeTo(new WritableStream(...)) 或更简单的 new Response(stream).blob()(现代浏览器支持):
-
response.blob()会等待整个流结束,适合“最终保存”场景 - 想边下载边显示进度,需自己累加
value.length并计算百分比 - 要实时写入磁盘(如 Service Worker 缓存),可用
WritableStream+TransformStream
注意事项和兼容性
不是所有环境都支持流:fetch 的 body 流在 Chrome 43+、Firefox 65+、Safari 16.4+ 支持;IE 完全不支持,需降级为普通请求或用 polyfill(但流功能无法真正模拟)。
- 服务端必须设置
Transfer-Encoding: chunked或正确设置Content-Length并分块输出 - 避免在流读取中做耗时同步操作,否则阻塞后续块处理;必要时用
setTimeout或queueMicrotask让出主线程 - CORS 场景下,服务端需明确允许
Content-Type和headers,且mode: 'cors'下不能省略Access-Control-Allow-Origin
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










