使用AJAX下载大型二进制文件断网时如何获取已接收的HTTP请求数据?
下载中断时保存已接收二进制数据的实现方法
核心原理
普通AJAX默认会等待全部响应数据接收完成后才对外暴露完整响应内容,要拿到中断前的部分数据,需要使用流式读取能力,在数据逐块到达时就进行暂存,触发断开事件时直接导出已暂存的数据。
可选实现方案
方案1:Fetch API + ReadableStream(主流浏览器适配,推荐)
Fetch API原生支持流式读取响应体,你可以逐块接收二进制数据,任意节点触发异常时都可以直接导出已接收的块:
- 调用
fetch()发起请求,从返回的Response对象中获取body对应的ReadableStream读取器 - 循环读取响应的chunk块,存入数组累积
- 监听请求错误或中断事件,触发时将已累积的chunk拼接为Blob导出到本地
示例代码:
async function streamDownload(url, fileName) { const chunks = []; let isCompleted = false; try { const res = await fetch(url); if (!res.ok) throw new Error(`请求失败,状态码:${res.status}`); const reader = res.body.getReader(); while (true) { const { done, value } = await reader.read(); if (done) { isCompleted = true; break; } chunks.push(value); // 可选:大文件场景下可定时将chunk写入IndexedDB,避免内存溢出 } } catch (err) { console.warn('下载中断,将导出已接收数据'); } finally { if (chunks.length && !isCompleted) { // 导出已下载内容 const blob = new Blob(chunks); const downloadLink = document.createElement('a'); downloadLink.href = URL.createObjectURL(blob); downloadLink.download = fileName; downloadLink.click(); URL.revokeObjectURL(downloadLink.href); } } }
方案2:XMLHttpRequest 兼容方案(适配老旧浏览器)
如果需要兼容不支持Fetch API的旧版浏览器,可以使用XHR的进度事件暂存已接收数据:
- 设置XHR的
responseType为arraybuffer,避免二进制数据被编码损坏 - 监听
progress事件,每次事件触发时将当前已接收的完整response暂存 - 触发
error中断事件时,直接将暂存的buffer转为Blob导出
示例代码:
function xhrDownload(url, fileName) { const xhr = new XMLHttpRequest(); xhr.open('GET', url); xhr.responseType = 'arraybuffer'; let receivedBuffer = null; xhr.addEventListener('progress', () => { if (xhr.response) receivedBuffer = xhr.response; }); // 下载中断触发 xhr.addEventListener('error', () => { if (!receivedBuffer) return; const blob = new Blob([receivedBuffer]); const downloadLink = document.createElement('a'); downloadLink.href = URL.createObjectURL(blob); downloadLink.download = fileName; downloadLink.click(); URL.revokeObjectURL(downloadLink.href); }); // 下载完成逻辑 xhr.addEventListener('load', () => { const blob = new Blob([xhr.response]); const downloadLink = document.createElement('a'); downloadLink.href = URL.createObjectURL(blob); downloadLink.download = fileName; downloadLink.click(); URL.revokeObjectURL(downloadLink.href); }); xhr.send(); }
注意事项
- 跨域场景下需要服务端配置对应的CORS规则,否则请求会被浏览器拦截
- 超过1GB的超大文件建议将接收的分片定时写入IndexedDB存储,避免内存占用过高导致页面崩溃
- 如果需要实现断点续传,可要求服务端支持
Range请求头,下次下载时携带Range: bytes=已下载字节数-即可从上次中断位置继续下载,拼接历史数据即可得到完整文件
内容的提问来源于stack exchange,提问作者waiaan
相关产品推荐
相关产品推荐

