无法让节点正确地将数据通过管道传输到下载文件

Cannot get node to pipe data to a download file correctly

我对节点和流式传输相当陌生,在尝试将大量数据流式传输到客户端浏览器上的文件时遇到问题。

例如,如果我在服务器上有一个大文件 test.txt,我可以通过设置 header 附件并将文件通过管道传输到请求响应如下。

res.setHeader('Content-Type', 'text/csv');
res.setHeader('Content-disposition', 'attachment;filename=myfile.text');

fs.createReadStream('./test.txt')
.pipe(res);

当用户单击该按钮时,下载开始,我们看到数据流式传输到下载文件中。该流需要几分钟,但在此期间客户端不会被阻止,他们可以在浏览器下载文件的同时继续做其他事情。

但是我的数据没有存储在文件中,我需要从另一台服务器一次检索一个字符串。所以我试图创建自己的读取流并逐块推送我的数据,但是当我这样做时它不起作用:

var s = new Readable();
s.pipe(res);

for(let i=0; i<=total; i++) {
  dataString = //code here to get next string needed to push
  s.push(dataString);
};
s.push(null);

使用此代码,当用户请求下载时,一旦下载开始,客户端将被阻塞,直到下载完成后才能进行任何其他操作。此外,如果数据流式传输的时间超过 30 秒,在这种情况下我们会遇到服务器超时,下载失败。对于文件流,这不是问题

如何让它像文件流一样工作,而不阻止客户端在下载时执行其他请求。我们将不胜感激任何关于实现这一点的最佳方式的建议。

我通过执行类似于此处的操作解决了此问题: How to call an asynchronous function inside a node.js readable stream

我的基本代码如下,这不会阻塞客户端或请求超时,因为数据会不断通过管道传输到客户端的文件下载。

res.setHeader('Content-Type', 'text/csv');
res.setHeader('Content-disposition', 'attachment;filename=myfile.text');

function MyStream() {
  var rs = new Readable();
  var hitsadded = 0;

  rs._read = function() {}; // needed to avoid "Not implemented" exception

  getResults(queryString, function getMoreUntilDone(err, res) {
      if (err){
        logger.logError(err);
      }

      rs.push(res.data);
      hitsadded += res.records;

      if (res.recordsTotal > hitsadded) {
        getNextPage(query, getMoreUntilDone);
      } else {
        rs.push(null);
      }
    });
  return rs;
}

 MyStream().pipe(zlib.createGzip()).pipe(res);