使用Koa将ExcelJS工作簿立即流式传输到浏览器



我想要的是将ExcelJS工作簿一点一点地流式传输到浏览器。问题是我对溪流感到很不舒服。

事实:

  • 我在Node JS v.18上
  • 我正在使用ExcelJS库的最后一个版本来生成一个大的Excel文件(v.4(
  • 我使用Koa的最新版本作为REST API工具(v.2(

这是我代码的简化部分。Excel工作簿还可以。如果我在内存中创建一个完整的缓冲区并将此缓冲区发送给Koa,我可以下载它。但当我试图流式传输并将流传递给Koa时,就会出现问题。将流传递到ExcelJS的方式是正确的,从他们的文档开始。

编辑

这是一个完整的工作基础(除了流(。

软件包.json

{
"name": "stackoverflow-exceljs-koa",
"private": true,
"version": "0.0.1",
"author": "rekam",
"dependencies": {
"exceljs": "^4.3.0",
"koa": "^2.13.4"
}
}

index.js

const Koa = require('koa');
const app = new Koa();
const { exportExcelData } = require('./builder');
app.use(async ctx => {
if (ctx.request.url === '/file') {
await exportExcelData('useFile', './test.xlsx');
ctx.body = 'Done, file saved at ' + __dirname + '/test.xlsx';
return;
}
if (ctx.request.url === '/stream') {
// const stream = new Stream();
// ctx.body = stream;
// await exportExcelData('useStream', stream);
ctx.body = 'to be implemented';
return;
}
ctx.body = 'Not Found';
ctx.status = 404;
});
app.listen(8101);  
console.log('visit http://localhost:8101/file or /stream');  

builder.js

const Excel = require('exceljs');
module.exports = {
async exportExcelData(type, streamOrFilename) {
const limit = 100;
let offset = 0;
const workbook = new Excel.stream.xlsx.WorkbookWriter({
stream: type === 'useStream' ? streamOrFilename : undefined,
filename: type === 'useFile' ? streamOrFilename : undefined,
useSharedStrings: true,
useStyles: true
});
const sheet = workbook.addWorksheet('Export');
sheet.columns = [{
header: 'ID',
key: 'id'
}];
const build = offset => new Promise(resolve => setTimeout(() => {
const rows = Array.from({ length: limit }).map((_, i) => ({ id: i + offset }));
if (offset > 10000) {
rows.pop(); // will break while looop
}
rows.forEach(row => sheet.addRow(row).commit());
return resolve(rows);
}, 1));
let rows;
do {
rows = await build(offset);
offset += limit;
} while (rows.length === limit);
sheet.commit();
await workbook.commit();
return;
}
};

使用

$ node index.js

我做了一些进一步的测试,由于其他相关问题,我找到了一个解决方案,就是这个:

const stream = ctx.res;
ctx.response.attachment('test.xlsx');
ctx.status = 200;
await exportExcelData('useStream', stream);
ctx.res.end();

当然,您需要捕获异常并调整ctx状态和主体响应。但有了这段代码,您将拥有任意GB的流式内容。

相关内容

最新更新