2

我(作为具有 Koa 框架的节点服务器)需要获取一个 JSON blob,将其转换为扩展名为 .json 的文件,然后将其粘贴到 zip 存档中,然后将存档作为文件附件发送以响应来自的请求客户端。

似乎这样做的方法是使用存档器工具。尽我所能理解,这样做的方法是创建一个存档,将一个 json 博客作为 .json 文件附加到它(它会自动在存档中创建文件?),然后将 .zip “管道”到响应对象. “管道”范式是我理解失败的地方,主要是由于没有得到这些文档所说的内容。

Archiver docs以及一些 stackoverflow答案使用的语言对我来说意味着“通过管道(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 文件在客户端下载,但 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();

逻辑:在“将流指向它”之后将主体设置为流确实看起来很愚蠢,因此请复制其他 stackoverflow 示例。

结果:与尝试 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)“神奇地行之有效”。这是存档工具示例文件的引用,“流魔术”是他们使用的词。

如何在内存中将 JSON blob 转换为 .json,然后将该 .json 附加到 .zip 中,然后将其发送到客户端并下载,然后可以成功解压缩以查看 .json

编辑:如果我 console.log the ctx.bodyafter archive.finalize(),它会显示 a ReadableStream,这似乎是正确的。但是,它有一个让我担心的“路径”属性——它是我想知道的 index.html——在客户端的“响应预览”中,我看到了我们的 index.html 的字符串化版本。该文件仍在下载.zip,所以我不太担心,但现在我想知道这是否相关。

EDIT2:深入研究客户端的响应,看起来发回的数据直接来自我们的 index.html,所以现在我很困惑。

4

2 回答 2

1

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我的流。

于 2021-07-02T10:59:43.077 回答
1

是的,您可以直接设置ctx.body为流。Koa 会处理管道。无需手动传输任何内容(例如,除非您还想通过管道传输到日志)。

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(); 
于 2019-03-11T11:05:02.600 回答