簡體   English   中英

NodeJS - 請求文件並壓縮它

[英]NodeJS - Request file and zip it

我目前正在為我的個人網站創建一個 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

閱讀此線程: 動態創建和流式傳輸 zip 到客戶端

@dankohn 提出了這樣的方法:

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

讓我假設我需要能夠從我的數據對象中提取流才能繼續。

我是在錯誤的軌道上還是我從根本上搞錯了?

編輯: lmao 感謝您解決我的問題我不知道發生了什么

使用歸檔器似乎是一種有效的方法,但是在將來自網絡的大數據輸入 zip 歸檔時,建議使用流。 否則,整個存檔數據將需要保存在內存中。

archiver 不支持從流中添加文件,但zip-stream支持。 對於從 Web 讀取流, 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()
})

使用異步/等待

您可以將其封裝成使用 async/await 的承諾,例如:

await new Promise((resolve, reject) => {
  zip.entry(stream, { name: elem.name }, err => {
    if (err) reject(err)
    resolve()
  }) 
})
zip.finalize()

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM