You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在下载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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.02 17:45:29