Создание 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();