Создание ZIP-архива в памяти с архиватором, а затем отправка этого файла клиенту с koa на сервер узла

Мне (как серверу узлов с каркасом Koa) нужно взять BLOB-объект JSON, превратить его в файл с расширением.json, затем вставить его в zip-архив, а затем отправить архив в виде вложения в ответ на запрос от клиент.

Кажется, способ сделать это - использовать инструмент архиватора. Насколько я понимаю, способ сделать это состоит в том, чтобы создать архив, добавить к нему блог json в виде файла.json (он автоматически создает файл в архиве?), А затем направить этот.zip в объект ответа., В парадигме "трубопровода" мое понимание терпит неудачу, в основном из-за того, что я не понимаю, что говорят эти документы.

Документы архиватора, а также некоторые ответы на вопросы stackru используют язык, который для меня означает "поток данных клиенту путем передачи (файл zip) в объект ответа HTTP. Документы Koa говорят, что ctx.body может быть установлен в поток напрямую, вот что я попробовал:

Попытка 1

    const archive = archiver.create('zip', {});
    ctx.append('Content-Type', 'application/zip');
    ctx.append('Content-Disposition', `attachment; filename=libraries.zip`);
    ctx.response.body = archive.pipe(ctx.body);
    archive.append(JSON.stringify(blob), { name: 'libraries.json'});
    archive.finalize();

Логика: тело ответа должно быть установлено в поток, и этот поток должен быть потоком архиватора (указывая на ctx.body).

Результат: файл.zip загружается на стороне клиента, однако почтовый индекс каким-то образом поврежден (не открывается).

Попытка 2

    const archive = archiver.create('zip', {});
    ctx.append('Content-Type', 'application/zip');
    ctx.append('Content-Disposition', `attachment; filename=libraries.zip`);
    archive.pipe(ctx.body);
    archive.append(JSON.stringify(blob), { name: 'libraries.json'});
    archive.finalize();

Логика: Задавать тело в качестве потока после "наведения на него потока" действительно глупо, поэтому вместо этого скопируйте другие примеры stackru.

Результат: То же, что и попытка 1.

Попытка 3

Основано на https://github.com/koajs/koa/issues/944

    const archive = archiver.create('zip', {});
    ctx.append('Content-Type', 'application/zip');
    ctx.append('Content-Disposition', `attachment; filename=libraries.zip`);
    ctx.body = ctx.request.pipe(archive);
    archive.append(JSON.stringify(body), { name: 'libraries.json'});
    archive.finalize();

Результат: ctx.request.pipe это не функция.

Вероятно, я не читаю это правильно, но все в Интернете, кажется, указывает на то, что делать archive.pipe(some sort of client-sent stream) "волшебно просто работает". Это цитата из файла примера инструмента архивации, "волшебство потоковой передачи" - это слова, которые они используют.

Как в оперативной памяти превратить BLOB-объект JSON в файл.json, а затем добавить этот файл.json в файл.zip, который затем отправляется клиенту и загружается, а затем может быть успешно разархивирован для просмотра файла.json?

РЕДАКТИРОВАТЬ: Если я console.log ctx.body после archive.finalize(), это показывает ReadableStreamчто кажется правильным. Однако у него есть свойство "путь", которое меня беспокоит - его index.html, о котором я задумывался, - в "предварительном просмотре ответа" на стороне клиента я вижу строковую версию нашего index.html. Файл все еще загружал.zip, так что я не был слишком обеспокоен, но теперь мне интересно, связано ли это.

РЕДАКТИРОВАТЬ 2: Глядя глубже в ответ на стороне клиента, кажется, что отправленные обратно данные прямо в наш index.html, так что теперь я очень запутался.

2 ответа

      
const passThrough = new PassThrough();
const archive = archiver.create('zip', {});

archive.pipe(passThrough);
archive.append(JSON.stringify(blob), { name: 'libraries.json'});
archive.finalize();

ctx.body = passThrough;
ctx.type = 'zip';

Это должно работать нормально для вашего варианта использования, поскольку архиватор на самом деле не является потоком, который мы должны передать ctx.body Наверное.

Да, вы можете напрямую установить ctx.body в поток. Коа позаботится о трубопроводе. Нет необходимости вручную что-либо передавать (если вы, например, не хотите передавать в журнал).

const archive = archiver('zip');

ctx.type = 'application/zip';
ctx.response.attachment('test.zip');
ctx.body = archive;

archive.append(JSON.stringify(blob), { name: 'libraries.json' });
archive.finalize(); 
Другие вопросы по тегам