Не удается скачать динамически созданный ZIP-архив
Я пытаюсь динамически записать вывод запросов MySQL в архив. Вот мой код:
var async = require("async");
var mysql = require("mysql");
var express = require("express");
var archiver = require("archiver");
var app = express();
var connection = mysql.createConnection({
host : 'localhost',
user : 'root',
password : 'password',
database : 'test'
});
app.get('/file', (req, res) => {
res.writeHead(200, {
'Content-Type': 'application/zip',
'Content-disposition': 'attachment; filename=archive-name.zip'
var zip = archiver('zip', {
zlib: { level: 9 }
});
zip.pipe(res);
zip.on('end', function() {
console.log('Archive wrote %d bytes', zip.pointer());
});
const queriesArray = ["SELECT * FROM tb1", "SELECT * FROM tb2"];
async.forEachOf(queriesList, (query) => {
connection.query(query, (err, results) => {
if(!err) {
zip.append(JSON.stringify(results), {name: `${query}.txt`})
}
else {
console.log("Error while performing Query");
}
})
}, function(err) {
if (err) {
console.log("error")
}
else {
zip.finalize();
}
})
})
const port = process.env.PORT || 7000;
app.listen(port, () => {
console.log('Listen on port ' + port);
})
Этот код должен создавать zip-архив с несколькими текстовыми файлами. Пользователь, посещающий /file
страница должна быть представлена с приглашением загрузить файл, но похоже, zip.finalize()
не работает, поэтому я не могу скачать созданный архив (загрузка начинается, когда я посещаю /file
но не заканчивается). Почему мой код не работает?
1 ответ
Это потому, что ваша функция обратного вызова никогда не вызывается как forEachOf
не знает, что он завершил все асинхронные задачи.
Функция iteratee имеет последний аргумент, который является функцией обратного вызова, которую вы должны вызвать, чтобы знать, что этот конкретный асинхронный процесс завершился, но вы никогда не используете его.
https://caolan.github.io/async/global.html
"Асинхронная функция" в контексте Асинхронная - это асинхронная функция с переменным числом параметров, причем последний параметр является обратным вызовом.
(function (arg1, arg2, ..., callback) {})
Финальный обратный вызов имеет видcallback(err, results...)
, который должен быть вызван после завершения функции.
Поэтому, чтобы исправить ваш код, обязательно вызовите метод обратного вызова вашей функции iteratee внутри обратного вызова вашего запроса.
async.forEachOf(queriesList, (query,key,callback) => {
connection.query(query, (err, results) => {
if(!err) {
zip.append(JSON.stringify(results), {name: `${query}.txt`})
}
else {
console.log("Error while performing Query");
}
callback();
})