0

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

因此,例如,如果在服务器上,如果我有一个大文件 test.txt,我可以通过设置标题附件并将文件传送到请求响应,轻松地将其流式传输到客户端浏览器,如下所示。

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 秒,在这种情况下,我们会遇到服务器超时,并且下载失败。使用文件流,这不是问题

如何让它像文件流一样运行,并且在下载时不阻止客户端执行其他请求。任何有关实施此方法的最佳方法的建议将不胜感激。

4

1 回答 1

0

我可以通过执行类似于此处的操作来解决此问题: 如何在 node.js 可读流中调用异步函数

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

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);
于 2018-05-04T16:25:44.080 回答