Экспресс-запрос больше не доступен для fileStream.on ('close') - PullRequest
0 голосов
/ 13 ноября 2018

У меня есть реализация POST-роутера в node.js с экспрессом. Тело поста представляет собой список файлов, и идея заключается в том, что эти файлы должны быть заархивированы и должна быть возвращена ссылка на полученный zip-файл. Я пытаюсь использовать «экспресс-сессию» для хранения прогресса с точки зрения количества заархивированных файлов, а также имени файла zip по завершении. Обновление количества заархивированных файлов (req.session.current) работает нормально, но по какой-то причине я не могу установить имя файла (req.session.zipFile) в сеансе, когда fileStream закрывается. Я подозреваю, что объект req больше не действителен к моменту достижения fileStream.on ('close'), но я не уверен, как с этим справиться. Я не могу получить доступ к данным сеанса без запроса. Это полная реализация маршрутизатора:

const express = require('express');
const router = express.Router();
const fs = require('fs');
const ZIP_FILES_PATH = require('../constants');


router.post('/', function(req, res, next){
    const json = JSON.parse(req.body.data);
    const path = json["base"];
    if (!path || path.length === 0){
        res.render("error", {msg: "JSON missing 'base'"})
        return;
    }
    const files = json["files"];
    if (!files || files.length === 0){
        res.statusCode = 400;
        res.send("JSON missing 'files'");
        return;
    }
    if (!fs.existsSync(path)) {
        res.statusCode = 400;
        res.send("Directory '" + path + "' does not exist");
        return;
    }
    try{
        var sessData = req.session;
            sessData.total = files.length ;
            sessData.current = 0;
            sessData.zipFile = '';
            zipFiles(path, files, req, res);
    }catch(error){
        res.statusCode = 500;
        res.send("The files could not be zipped");
        return;
    }
    res.render("zipping")
});
module.exports = router;

const zipFiles = (path, files, req, res) => {
    const zipFile = require('crypto').createHash('md5').update(path).digest("hex") + "_" + new Date().getTime() + ".zip";
    const archiver = require('archiver');
    const fileStream = fs.createWriteStream(ZIP_FILES_PATH + zipFile);
    const archive = archiver('zip', {
    gzip: true,
    zlib: { level: 9 }
    });

    archive.on('error', function(err) {
        throw err;
    });
    fileStream.on('close', function() {
        req.session.zipFile = "/download?file=" + zipFile; //Doesn't stick!
    });
    archive.pipe(fileStream);
    files.map(file => zipSingleFile(path, file, req, archive));
    archive.finalize();

}
const zipSingleFile = (path, file, req, archive)  => {
    fs.existsSync(path + "/" + file) ? archive.file(path + "/" + file, { name: file }) : null;
    req.session.current = req.session.current + 1;
}

1 Ответ

0 голосов
/ 13 ноября 2018

zipFiles() является асинхронным. Это означает, что он не блокируется и заканчивается через некоторое время. Итак, в процессе обработки вашего запроса вы звоните

res.render("zipping")

до окончания zipFiles(). И, res.render() отправит ответ и закроет выходной поток.

Если вы хотите подождать, чтобы позвонить res.render(), пока не закончите вызов zipFiles(), то вам нужно либо позвонить изнутри zipFiles(), когда все будет сделано, либо добавить обратный вызов к zipFiles() чтобы он мог общаться, когда закончил.

Кроме того, есть ли причина, по которой вы не можете установить req.session.zipFile = "/download?file=" + zipFile; до того, как позвоните res.render()?


Кроме того, в зависимости от того, как настроен ваш сеанс (для которого вы не показываете нам код), просто сделайте это:

req.session.zipFile  = "/download?file=" + zipFile;

может быть недостаточно для фактического сохранения этого значения в сеансе. Возможно, вам также придется позвонить .save() во время сеанса.


И вы устанавливаете:

req.session.zipFile

в конце процесса архивирования, поэтому любые запросы, поступающие из этого сеанса до его завершения, также не увидят, что эта переменная сеанса также установлена ​​(для меня это проблема параллелизма).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...