Hep*_*ous 6 javascript encryption download file-storage
我想从我的服务器下载加密文件,解密并在本地保存.我想解密文件并在下载时将其写入本地,而不是等待下载完成,解密,然后将解密文件放在锚标记中.我想这样做的主要原因是,对于大文件,浏览器不必在内存中存储数百兆字节或几千兆字节.
只有将Service Worker + Fetch + Stream结合使用,这才可能实现
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)cuz StreamSaver依赖于fetch + ReadableStream的任何方式并且不能以任何其他方式使用
稍后,当WritableStream + Transform流也实现时,您将可以执行类似的操作
fetch(url).then(res => {
    const fileStream = streamSaver.createWriteStream('filename.txt')
    res.body
        .pipeThrogh(unencrypt)
        .pipeTo(fileStream)
        .then(done)
})
还值得一提的是,默认下载管理器通常与后台下载相关联,因此ppl有时会在看到下载内容时关闭该选项卡。但这都是在主线程中发生的,因此您需要在用户离开时警告用户
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
}
新的解决方案已经到来:showSaveFilePicker/ FileSystemWritableFileStream,自 2020 年底以来在 Chrome 和所有主要衍生产品(包括 Edge 和 Opera)中受支持,并且带有适用于 Firefox 和 Safari的垫片(由另一个主要答案的作者编写!)直接执行此操作:
async function streamDownloadDecryptToDisk(url, DECRYPT) {\n\n    // create readable stream for ciphertext\n    let rs_src = fetch(url).then(response => response.body);\n\n    // create writable stream for file\n    let ws_dest = window.showSaveFilePicker().then(handle => handle.createWritable());\n\n    // create transform stream for decryption\n    let ts_dec = new TransformStream({\n        async transform(chunk, controller) {\n            controller.enqueue(await DECRYPT(chunk));\n        }\n    });\n\n    // stream cleartext to file\n    let rs_clear = rs_src.then(s => s.pipeThrough(ts_dec));\n    return (await rs_clear).pipeTo(await ws_dest);\n\n}\n根据性能\xe2\x80\x94,如果您试图与 MEGA 竞争,例如\xe2\x80\x94,您也可以考虑修改DECRYPT(chunk)以允许您使用ReadableStreamBYOBReader它:
\n\n\xe2\x80\xa6 从底层字节源零复制读取。它用于从底层源进行高效复制,其中数据作为“匿名”字节序列(例如文件)传递。
\n
| 归档时间: | 
 | 
| 查看次数: | 2803 次 | 
| 最近记录: |