【问题标题】:NodeJS - Request file and zip itNodeJS - 请求文件并压缩它
【发布时间】:2018-02-06 06:17:17
【问题描述】:

我目前正在为我的个人网站创建一个 REST API。我想包括一些下载,并且我想提供选择多个下载并将它们作为 zip 文件下载的可能性。 我的第一个方法很简单:带有 url 的数组,请求每个 URL,压缩它,发送给用户,删除。但是,我认为这种方法太肮脏了,考虑到周围有像流这样的东西似乎很适合这个东西。

现在,我尝试过,目前正在努力解决在不同范围内处理流和事件的基本概念。

以下工作:

const r = request(url, options);
r.on('response', function(res) {
    res.pipe(fs.createWriteStream('./file.jpg'));
});

据我了解,在这种情况下 r 是一个传入流,我在其上侦听响应事件,一旦它发生,我将其通过管道传输到用于写入文件系统的流。

我的第一步是重构它,使它更适合我的情况,但我在这里已经失败了:

async function downloadFile(url) {
    return request({ method: 'GET', uri: url });
}

现在我想使用一个函数,它使用不同的 url 调用“downloadFile()”,并再次使用 createWriteStream() 将所有这些文件保存到磁盘:

const urls = ['https://download1', 'https://download2', 'https://download3'];
urls.forEach(element => {
    downloadFile(element).then(data => {
        data.pipe(fs.createWriteStream('file.jpg'));
    });
});

使用调试器我发现数据对象中不存在“响应”事件——也许这已经是问题所在了?此外,我认为 data.body 包含我下载的文档的字节(在本例中为 pdf),所以我想知道是否可以将其流式传输到其他地方?

在阅读了一些 stackoveflow 线程后,我发现了以下模块:archiver

阅读本帖:Dynamically create and stream zip to client

@dankohn 提出了类似的方法:

archive
  .append(fs.createReadStream(file1), { name: 'file1.txt' })
  .append(fs.createReadStream(file2), { name: 'file2.txt' });

让我假设我需要能够从我的数据对象中提取流才能继续。

我是在错误的轨道上还是我从根本上搞错了?

编辑:lmao 感谢您解决我的问题,我不知道发生了什么

【问题讨论】:

    标签: javascript node.js download archive


    【解决方案1】:

    使用归档器似乎是一种有效的方法,但是在将来自网络的大数据输入 zip 归档时,建议使用流。否则,整个存档数据将需要保存在内存中。

    archiver 不支持从流中添加文件,但 zip-stream 支持。要从网络上读取流,request 会派上用场。

    示例

    // npm install -s express zip-stream request
    
    const request = require('request');
    const ZipStream = require('zip-stream');
    const express = require('express');
    
    const app = express();
    
    app.get('/archive.zip', (req, res) => {
        var zip = new ZipStream()
        zip.pipe(res);
    
        var stream = request('https://loremflickr.com/640/480')
        zip.entry(stream, { name: 'picture.jpg' }, err => {
            if(err)
                throw err;          
        })
    
        zip.finalize()
    });
    
    app.listen(3000)
    

    更新:使用多个文件的示例

    zip.entry()的回调函数中添加递归处理下一个文件的例子。

    app.get('/archive.zip', (req, res) => {
        var zip = new ZipStream()
        zip.pipe(res);
    
        var queue = [
            { name: 'one.jpg', url: 'https://loremflickr.com/640/480' },
            { name: 'two.jpg', url: 'https://loremflickr.com/640/480' },
            { name: 'three.jpg', url: 'https://loremflickr.com/640/480' }
        ]
    
        function addNextFile() {
            var elem = queue.shift()
            var stream = request(elem.url)
            zip.entry(stream, { name: elem.name }, err => {
                if(err)
                    throw err;
                if(queue.length > 0)
                    addNextFile()
                else
                    zip.finalize()
            })
        }
    
        addNextFile()
    })
    

    【讨论】:

    • 我遇到的 zip-stream 问题不支持排队,我不确定如何处理
    • 该死的你很快,非常感谢!我发现了这个:stackoverflow.com/questions/12359450/… 并且只是像那样集成它(不像你那么干净)
    猜你喜欢
    • 1970-01-01
    • 2012-08-22
    • 2019-03-23
    • 2013-10-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多