[英]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.