fetch本身不直接提供实时上传/下载进度,需结合readablestream(下载)或transformstream/手动分块(上传)实现;下载时用response.body.getreader()逐块读取并累加字节数,上传则需构造可读流并在enqueue时计数,或退用xmlhttprequest原生支持progress事件。

fetch 本身不直接提供实时的上传/下载字节数,因为它是一个高层 API,封装了底层网络操作。要获取真实的进度(比如已上传多少字节、还剩多少),需要结合 ReadableStream(下载)和 TransformStream 或手动分块发送(上传)来实现流式处理与计数。
下载进度:用 response.body.getReader() 读取流并累加
服务端需支持流式响应(如 Node.js 的 res.write() 分块发送),前端通过 response.body 获取可读流,逐块读取并统计已接收字节数:
- 调用
response.body.getReader()得到流读取器 - 循环调用
reader.read(),每次返回{ done, value },其中value是Uint8Array - 累加
value.length即为已下载字节数 - 配合
Content-Length响应头可计算百分比(但注意:流式响应可能不带该头,此时只能显示“已接收 X 字节”)
上传进度:不能直接用 fetch body,需手动分块 + ReadableStream
原生 fetch 的 body(如 FormData、ArrayBuffer)是一次性提交,无法监听进度。真实上传进度需自己构造可读流,并在读取时计数:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- 将文件转为
ArrayBuffer或使用file.stream()获取其原始流 - 用
new ReadableStream({ pull(controller) { ... } })包装,在pull中分块读取源数据并调用controller.enqueue(chunk) - 每 enqueue 一次就更新已上传字节数,并触发自定义进度事件或回调
- 最后把该流作为 fetch 的
body,并设置headers: { 'Content-Type': '...' }(注意服务端需能解析流)
更简单可靠的方案:用 XMLHttpRequest(XHR)
如果只需兼容性和开发效率,XHR 仍是获取上传/下载进度最直接的方式:
-
xhr.upload.onprogress = e => { e.loaded / e.total }直接拿到上传进度 -
xhr.onprogress = e => { e.loaded / e.total }拿到下载进度 - 无需手动流处理,浏览器原生支持,且
Content-Length自动可用 - 现代项目中可封装成 Promise + 进度回调的工具函数,体验接近 fetch
注意事项与常见坑
实际使用中容易忽略的关键点:
- 服务端必须启用流式传输(如 Express 中禁用
res.flush()、Nginx 需关闭proxy_buffering) - CORS 场景下,服务端需显式允许
Content-Range等进度相关 header(如Access-Control-Expose-Headers: Content-Length, X-Progress) - fetch 不支持上传
onprogress,强行用body: new Blob([data])仍是一次性发送,无法监控中间状态 - Safari 对
ReadableStream支持较晚(iOS 16.4+),需检查运行环境或降级
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










