Http Fetch+StreamSaver.js分片下载大文件
目前前端没有很好的api支持流式的文件的分片下载。如果直接把整个文件保存到Blob对象中再保存,有可能出现很多不可以预期的问题,可能会因为达到浏览器的Blob对象上限而下载失败。也有机会因为客户端内存太低而导致OOM。那如果我们有额外的文件服务器的话,可以选择把文件先导出到文件服务器,然后前端再通过文件路径由浏览器处理下载。但是如果又没有额外的文件服务器,又想要支持分片下载,这就是这篇文章的主题。
StreamSaver.js的工作原理
StreamSaver.js采用了不同的方法。现在,您可以创建一个直接到文件系统的可写流,而不是将数据保存在客户端存储或内存中(我说的不是chromes沙盒文件系统或任何其他网络存储)。这是通过模拟服务器如何指示浏览器使用某个响应头+服务工作者来保存文件来实现的 如果您试图保存的文件来自云/服务器,请使用服务器,而不是模拟浏览器使用StreamSaver在磁盘上保存文件的操作。添加那些额外的响应头,不要使用AJAX来获取它。FileSaver有一个很好的关于使用头的wiki。如果您无法更改标题,那么您可以使用StreamSaver作为最后手段。FileSaver、streamsaver和其他类似的应用程序主要用于浏览器内客户端生成的内容。
StreamSaver.js通过伪造一个服务器文件的链接,伪造的服务器收文件下载到请求返回Content-Disposition头告诉浏览器开始下载文件。但实际上这个文件服务器并不存在并且内容也不在服务器上。因此,他的解决方案是创建一个Service Worker(sw.js),它可以拦截请求并使用responsdWith()伪装成服务器。
中间人MITM
既然是伪造的服务器,那必然涉及到中间人,默认StreamSaver.js的MITM是https://jimmywarting.github.io/StreamSaver.js/mitm.html?version=2.0.0。
如果你的客户端是联网的而且是可以访问github那没有问题,那如果你的站点是内网或客户端根本无法访问github那问题就来了,下载根本无法触发。
在JavaScript中,MITM代表"Man-in-the-Middle",这是一种网络攻击技术。在这种攻击中,攻击者秘密地插入他们自己的设备或软件,从而在一个两方或多方的通信中间接收、修改、甚至拦截消息。这种攻击可以在没有任何一方知道的情况下进行。在JavaScript中,你可能会在谈到网络安全性时听到MITM,尤其是在处理如HTTPS这样的安全协议时。在这些情况下,JavaScript可能会使用一些API或技术(例如Service Workers)来尝试防止或检测MITM攻击。
自部署MITM:
- 下载文件
- https://github.com/jimmywarting/StreamSaver.js/blob/master/mitm.html
- https://github.com/jimmywarting/StreamSaver.js/blob/master/sw.js
- 把下载的文件放入项目目录
目录:./public
StreamSaver.js整合
- 安装
npm install streamsaver --save
- 引入依赖
import * as streamSaver from 'streamsaver'
- 下载方法封装
export async function download(url, parameters, fileName) { streamSaver.mitm = 'https://xxxx/mitm.html?version=2.0.0' const fileStream = streamSaver.createWriteStream(fileName) return fetch(url, { method: 'POST', body: JSON.stringify(parameters), cache: 'no-cache', headers: { 'Content-Type': 'application/json' } }).then(res => { const readableStream = res.body if (window.WritableStream && readableStream.pipeTo) { return readableStream.pipeTo(fileStream) } window.writer = fileStream.getWriter() const reader = res.body.getReader() const pump = () => reader.read() .then(res => res.done ? window.writer.close() : window.writer.write(res.value).then(pump)) pump() }) }
- MITM设置
本地调试,设置中间人为localhost地址:
streamSaver.mitm = 'http://localhost:9527/mitm.html?version=2.0.0'
线上设置中间人为生产地址:
streamSaver.mitm = 'https://xxxx/mitm.html?version=2.0.0'
参考:
- https://juejin.cn/post/6926447267452813325
- https://github.com/jimmywarting/StreamSaver.js
- 原理解释:https://juejin.cn/post/6985883442122604574
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 清华大学推出第四讲使用 DeepSeek + DeepResearch 让科研像聊天一样简单!
· 推荐几款开源且免费的 .NET MAUI 组件库
· 实操Deepseek接入个人知识库
· 易语言 —— 开山篇
· 【全网最全教程】使用最强DeepSeekR1+联网的火山引擎,没有生成长度限制,DeepSeek本体