fetch 本身不直接提供上传/下载进度回调,但可通过 readablestream(下载)和自定义流(上传)结合 progress 事件或流式读写实现近实时进度追踪;关键在于绕过 fetch 黑盒、手动控制数据流。

Fetch 本身不直接提供上传/下载进度回调,但可以通过 ReadableStream(下载)和 ReadableStream + FormData 自定义流(上传)结合 progress 事件模拟 或 流式读取/写入 实现近实时的进度追踪。关键在于绕过 Fetch 的黑盒处理,手动控制数据流。
下载大文件时获取实时进度
利用 response.body 返回的 ReadableStream,逐块读取并累加已接收字节数:
- 调用
fetch(url)后,先检查response.headers.get('content-length')获取总大小(若服务端支持 CORS 并暴露该 header) - 用
response.body.getReader()获取流读取器,循环调用reader.read() - 每次
read()返回的{ done, value }中,value是Uint8Array,其.length即本次接收字节数 - 累加字节数,除以总大小即得当前进度(注意:若无
content-length,只能显示“已接收 X 字节”,无法算百分比)
上传大文件时获取实时进度
标准 fetch(url, { method: 'POST', body: file }) 不暴露上传过程。可行方案有两种:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
-
方案一(推荐):用
ReadableStream包装文件,手动分块读取并上报进度
创建自定义流,用file.stream().getReader()读取文件块,在每次read()后触发自定义进度事件,再将块拼成Uint8Array写入Request的 body(需配合body: stream和后端流式接收) -
方案二(兼容性好):退回到
XMLHttpRequest
它原生支持upload.onprogress事件,可精确监听上传字节数;适合仍需强进度反馈且不强制用 Fetch 的场景
注意事项与常见坑
实际使用中需注意:
-
content-length需服务端在响应头中添加Access-Control-Expose-Headers: content-length,否则 JS 无法读取 - 上传时若用
FormData,内部会自动加 boundary,无法流式控制——必须避免直接传new FormData().append('file', file) - 流式上传要求后端支持分块接收(如 Node.js 的
req.on('data', chunk => {...})),不能依赖传统req.body - 浏览器对流读取有微任务调度,频繁更新 UI 可节流(如每 100ms 更新一次进度条)
简单示例:下载进度(带 content-length)
代码逻辑示意(省略错误处理):
const response = await fetch('/large.zip');
const total = Number(response.headers.get('content-length'));
const reader = response.body.getReader();
let loaded = 0;
<p>while (true) {
const { done, value } = await reader.read();
if (done) break;
loaded += value.length;
const progress = total ? Math.round((loaded / total) * 100) : null;
console.log(<code>已下载 ${loaded} / ${total} bytes (${progress}%)</code>);
}
</p>Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










