如何让客户端下载一个动态生成的非常大的文件

Sim*_*oyw 4 queue jobs redis node.js kue

我有一个导出函数,它读取整个数据库并创建一个包含所有记录的.xls文件.然后将文件发送到客户端.

当然,导出完整数据库的时间需要很多时间,并且请求很快就会以超时错误结束.

处理这种情况的最佳解决方案是什么?

我听说过一些关于使用Redis建立队列的事情,但这需要两个请求:一个用于启动将生成文件的作业,另一个用于下载生成的文件.

这是否可以通过客户的单一请求进行?

S.D*_*.D. 10

Excel导出:

使用Streams.以下是可能做的大致的概念:

  1. 使用exceljs模块.因为它有一个针对这个确切问题的流API.

    var Excel = require('exceljs')
    
    Run Code Online (Sandbox Code Playgroud)
  2. 因为我们正在尝试启动下载.将适当的标题写入响应.

    res.status(200);
    res.setHeader('Content-disposition', 'attachment; filename=db_dump.xls');
    res.setHeader('Content-type', 'application/vnd.ms-excel');
    
    Run Code Online (Sandbox Code Playgroud)
  3. 创建由Streaming Excel writer支持的工作簿.给写入器的流是服务器响应.

    var options = {
        stream: res, // write to server response
        useStyles: false,
        useSharedStrings: false
    };
    
    var workbook = new Excel.stream.xlsx.WorkbookWriter(options);
    
    Run Code Online (Sandbox Code Playgroud)
  4. 现在,输出流媒体流都已设置完毕.对于输入流,更喜欢将查询结果/光标作为流提供的数据库驱动程序.

  5. 定义一个异步函数,将1个表转储到1个工作表.

    var tableToSheet = function (name, done) {
        var str = dbDriver.query('SELECT * FROM ' + name).stream();
        var sheet = workbook.addWorksheet(name);
    
        str.on('data', function (d) {
            sheet.addRow(d).commit(); // format object if required
        });
    
        str.on('end', function () {
            sheet.commit();
            done();
        });
    
        str.on('error', function (err) {
            done(err);
        });
    }
    
    Run Code Online (Sandbox Code Playgroud)
  6. 现在,让我们使用async模块的mapSeries导出一些db表:

    async.mapSeries(['cars','planes','trucks'],tableToSheet,function(err){
       if(err){
         // log error
       }
       res.end();
    })
    
    Run Code Online (Sandbox Code Playgroud)

CSV导出:

对于单个表/收集模块的CSV导出,可以使用fast-csv:

// response headers as usual
res.status(200);
res.setHeader('Content-disposition', 'attachment; filename=mytable_dump.csv');
res.setHeader('Content-type', 'text/csv');

// create csv stream
var csv = require('fast-csv');
var csvStr = csv.createWriteStream({headers: true});

// open database stream
var dbStr = dbDriver.query('SELECT * from mytable').stream();

// connect the streams
dbStr.pipe(csvStr).pipe(res);
Run Code Online (Sandbox Code Playgroud)

您现在正在将数据从数据库传输到HTTP响应,并将其转换为xls/csv格式.无需将整个数据缓冲或存储在内存或文件中.