fetch下载文件需分场景:小文件用response.blob()转blob下载;大文件用readablestream流式读取并监控进度;断点续传需后端支持range请求;注意跨域、dom挂载、浏览器兼容性及移动端限制。

JavaScript 的 fetch 本身不直接保存文件到本地,但可以通过获取响应流(Response.body)配合 ReadableStream 和 Blob 实现可控的文件下载与保存,尤其适合大文件、进度监控或自定义处理场景。
获取响应流并转为 Blob 下载
这是最常用的方式:用 fetch 请求文件资源,调用 response.blob() 得到二进制对象,再用 URL.createObjectURL 创建临时链接触发下载。
- 适用于大多数静态资源(PDF、图片、ZIP 等),代码简洁可靠
- 注意:整个文件会先加载进内存,超大文件(如 >500MB)可能引发内存压力
- 示例:
async function downloadFile(url, filename) {
try {
const response = await fetch(url);
if (!response.ok) throw new Error(`HTTP ${response.status}`);
const blob = await response.blob();
const blobUrl = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = blobUrl;
a.download = filename || (response.headers.get('content-disposition')?.match(/filename[^;=\n]*=([^;\n]*)/)?.[1] || 'download');
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
URL.revokeObjectURL(blobUrl); // 及时释放内存
} catch (err) {
console.error('下载失败:', err);
}
}
流式读取 + 进度监听(适合大文件)
对超大文件或需显示下载进度的场景,可直接读取 response.body 的 ReadableStream,逐块处理,避免一次性加载全部内容。
- 用
response.body.getReader()获取流读取器,配合read()按 chunk 读取 - 每读一块就累加已下载字节数,可用于更新 UI 进度条
- 最终将所有 chunks 合并为
Uint8Array,再构造Blob
async function streamDownload(url, filename) {
const response = await fetch(url);
if (!response.ok) throw new Error();
const contentLength = response.headers.get('content-length');
const total = contentLength ? parseInt(contentLength) : null;
let loaded = 0;
const reader = response.body.getReader();
const chunks = [];
while (true) {
const { done, value } = await reader.read();
if (done) break;
chunks.push(value);
loaded += value.length;
// 可在此更新进度:console.log(`${loaded}/${total} bytes`);
}
const allBytes = new Uint8Array(
chunks.reduce((acc, chunk) => acc + chunk.length, 0)
);
let offset = 0;
for (const chunk of chunks) {
allBytes.set(chunk, offset);
offset += chunk.length;
}
const blob = new Blob([allBytes], { type: response.headers.get('content-type') || 'application/octet-stream' });
const blobUrl = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = blobUrl;
a.download = filename;
a.click();
URL.revokeObjectURL(blobUrl);
}
后端配合:支持断点续传与分块下载
若需真正健壮的大文件下载(如网络中断后恢复),仅前端流式读取不够,还需后端支持 Range 请求头和 206 Partial Content 响应。
- 前端用
headers: { Range: 'bytes=0-1023' }请求指定区间 - 服务端返回
Content-Range和对应字节段,前端拼接多个片段 - 需自行管理已下载偏移量、重试逻辑、校验和等,复杂度显著上升
- 一般推荐使用成熟方案(如
axios+ 自定义 adapter 或专用库如downloadjs)
注意事项与兼容性
部分细节容易忽略,影响稳定性:
-
response.blob()在 Safari 中对跨域资源可能受限,确保服务端设置了Access-Control-Allow-Origin和Access-Control-Expose-Headers: Content-Disposition - 动态创建的
<a></a>标签必须 append 到 DOM 才能触发click()(否则部分浏览器静默失败) - IE 不支持
fetch和ReadableStream,需降级为XMLHttpRequest或使用 polyfill - 移动端 Safari 对自动下载有限制(如非用户手势触发会失败),务必确保调用在点击事件等合法上下文中
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











