JavaScript: 写入下载流

JavaScript: Writing to download stream

我想从我的服务器下载一个加密文件,解密并保存在本地。我想解密文件并在下载时将其写入本地,而不是等待下载完成,解密它,然后将解密的文件放在锚标记中。我想这样做的主要原因是,对于大文件,浏览器不必在内存中存储数百兆字节或几千兆字节。

这只有通过服务工作者 + 获取 + 流的组合才能实现 一些浏览器有 worker 和 fetch,但支持 fetch with streaming (Blink) 的更少

new Response(new ReadableStream({...}))

我已经构建了一个流式文件保护程序库来与其他服务工作者通信以拦截网络请求:StreamSaver.js

它与节点的流有点不同这里是一个例子

function unencrypt(){
    // should return Uint8Array
    return new Uint8Array()
}

// We use fetch instead of xhr that has streaming support
fetch(url).then(res => {
    // create a writable stream + intercept a network response
    const fileStream = streamSaver.createWriteStream('filename.txt')
    const writer = fileStream.getWriter()

    // stream the response
    const reader = res.body.getReader()
    const pump = () => reader.read()
        .then(({ value, done }) => {
            let chunk = unencrypt(value)

            // Write one chunk, then get the next one
            writer.write(chunk) // returns a promise

            // While the write stream can handle the watermark,
            // read more data
            return writer.ready.then(pump)
        )

    // Start the reader
    pump().then(() =>
        console.log('Closed the stream, Done writing')
    )
})

还有其他两种方法可以使用 xhr 获得流式响应,但它不是标准的,如果你使用它们也不会影响 (responseType = ms-stream || moz-chunked-arrayBuffer) 因为 StreamSaver 取决于fetch + ReadableStream 任何方式,不能以任何其他方式使用

稍后,当 WritableStream + Transform 流也得到实现时,您将能够执行类似的操作

fetch(url).then(res => {
    const fileStream = streamSaver.createWriteStream('filename.txt')

    res.body
        .pipeThrogh(unencrypt)
        .pipeTo(fileStream)
        .then(done)
})

还值得一提的是,默认下载管理器通常与后台下载相关联,因此人们有时会在看到下载时关闭该选项卡。但这一切都发生在主线程中,因此您需要在用户离开时警告他们

window.onbeforeunload = function(e) {
  if( download_is_done() ) return

  var dialogText = 'Download is not finish, leaving the page will abort the download'
  e.returnValue = dialogText
  return dialogText
}

出于安全原因,浏览器不允许将传入的可读流直接通过管道传输到本地文件系统,因此您有两种解决方法:

  1. window.open(Resource_URL): 下载资源到新的window Content_Disposition 设置为“附件”;
  2. <a download href="path/to/resource"></a>:使用“下载”属性 AnchorElement下载流到硬盘;

希望这些对您有所帮助:)