如何在下载octet-stream流过程中实时写入文件?
要实现流式边下载边存文件,jQuery AJAX的方案行不通——传统XHR的progress事件只能拿到进度数值,拿不到实际的响应流数据。得换用Fetch API结合StreamSaver.js来实现,下面针对你的疑问逐一解决:
1. 如何获取response.body.getReader()?
jQuery封装的AJAX基于传统XMLHttpRequest,而response.body是Fetch API里Response对象的专属特性,传统XHR不支持直接获取可读取的流(即便强制设置responseType: "stream",兼容性也极差)。直接替换成Fetch API,就能在响应回调里拿到response.body,进而调用.getReader()逐块读取数据。
2. 如何边下载边保存文件?
用StreamSaver.js创建浏览器端的可写流(WritableStream),然后把Fetch获取到的响应流直接"管道"到这个可写流,浏览器会自动将接收到的每一块数据写入本地文件,无需等待整个文件下载完成。
完整实现代码
替换你原来的jQuery AJAX代码,改用以下方案:
// 获取CSRF Token const csrfToken = get_CSRF_TOKEN(); const apiURL = "你的接口地址"; const strCustomData = "你的自定义数据"; // 发起Fetch请求 fetch(apiURL, { method: "POST", headers: { "Content-Type": "application/json; charset=utf-8", "RequestVerificationToken": csrfToken }, body: JSON.stringify(strCustomData) }) .then(response => { // 处理响应错误 if (!response.ok) { throw new Error(`请求失败: ${response.statusText}`); } // 从响应头解析文件名 const contentDisposition = response.headers.get("Content-Disposition") || ""; let fileName = "File_Not_Found.zip"; const fileNameMatch = contentDisposition.match(/filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/); if (fileNameMatch?.[1]) { fileName = decodeURIComponent(fileNameMatch[1].replace(/['"]/g, "")); } // 创建StreamSaver可写流,传入文件名和总大小(用于进度计算) const fileStream = streamSaver.createWriteStream(fileName, { size: parseInt(response.headers.get("Content-Length") || 0) }); // 流式读取响应并写入文件,同时统计进度 const reader = response.body.getReader(); const totalSize = parseInt(response.headers.get("Content-Length") || 0); let loadedSize = 0; function readAndWriteChunk() { return reader.read().then(({ done, value }) => { if (done) { console.log("下载完成"); fileStream.close(); return; } // 更新进度,这里可以替换成你的进度条DOM更新逻辑 loadedSize += value.length; const progress = (loadedSize / totalSize) * 100; console.log(`当前进度: ${progress.toFixed(2)}%`); // 将当前数据块写入文件流,继续读取下一块 return fileStream.write(value).then(readAndWriteChunk); }); } return readAndWriteChunk(); }) .catch(error => { console.error("下载出错:", error); // 这里添加自定义错误提示逻辑 });
关键注意事项
- 为什么弃用jQuery AJAX?:传统XHR的
onprogress只能拿到已下载字节数,无法获取具体的响应数据块,根本没法实现边下载边写入文件的逻辑,Fetch API的ReadableStream才是标准的流式处理方案。 - StreamSaver.js的正确姿势:不需要在AJAX的
onprogress里调用,直接对接Fetch的响应流即可,通过手动读取分块或pipeTo方法,就能实现流式写入。 - ASP.NET Core后端配置:确保接口返回分块传输响应(大文件默认启用),正确设置
Content-Disposition头,同时验证CSRF Token的有效性。
内容的提问来源于stack exchange,提问作者Codingwiz
相关产品推荐
相关产品推荐

