使用expressjs无法将响应流式传输到客户端

时间:2014-08-08 14:44:47

标签: node.js express streaming

在使用Nodejs / Expressjs时,我很难绕过如何将数据流回客户端。

我从我的数据库中获取大量数据并且我正在以块的形式进行操作,我希望将其传输回客户端,因为我获取的数据使得我不必将整个数据集存储在内存中发送回来之前的json对象。

我希望数据作为文件流回,即我希望浏览器询问我的用户如何处理下载文件。我以前创建了一个文件系统写入流并将我的数据内容流式传输到文件系统,然后在完成后我将文件发送回客户端。我想消除中间人(在文件系统上创建tmp文件)并将数据流传输到客户端。

  app.get(
    '/api/export',
    function(req, res, next) {
      var notDone = true;
      while (notDone) {
         var partialData = // grab partial data from database (maybe first 1000 records);

         // stream this partial data as a string to res???

         if (checkIfDone) notDone = false;
      }
    }
  );

我可以调用res.write("一些字符串数据"),然后在完成后调用res.end()。但是,我并不是100%确定这实际上是在我写的时候将响应流式传输到客户端。看起来像expressjs存储所有数据,直到我调用end然后发送响应。这是真的吗?

使用expressjs将字符串数据块流式传输到响应的正确方法是什么?

2 个答案:

答案 0 :(得分:9)

response对象已经是可写流。 Express处理自动发送分块数据,因此您不需要做任何额外的事情,但是:

response.send(data)

您可能还想查看内置管道方法http://nodejs.org/api/stream.html#stream_event_pipe

答案 1 :(得分:4)

您可以通过设置适当的标题然后只写入响应对象来完成此操作。例如:

res.writeHead(200, {
  'Content-Type': 'text/plain',
  'Content-Disposition': contentDisposition('foo.data')
});
var c = 0;
var interval = setInterval(function() {
  res.write(JSON.stringify({ foo: Math.random() * 100, count: ++c }) + '\n');
  if (c === 10) {
    clearInterval(interval);
    res.end();
  }
}, 1000);


// extracted from Express, used by `res.download()`
function contentDisposition(filename) {
  var ret = 'attachment';
  if (filename) {
    filename = basename(filename);
    // if filename contains non-ascii characters, add a utf-8 version ala RFC 5987
    ret = /[^\040-\176]/.test(filename)
      ? 'attachment; filename="' + encodeURI(filename) + '"; filename*=UTF-8\'\'' + encodeURI(filename)
      : 'attachment; filename="' + filename + '"';
  }

  return ret;
}

此外,Express / node不会缓冲写入套接字的数据,除非套接字暂停(显式或隐式地由于背压)。当处于该暂停状态时由节点缓冲的数据可以或可以不与已经缓冲的其他数据块组合。您可以检查res.write()的返回值,以确定是否应继续写入套接字。如果它返回false,则听取' drain'事件,然后再继续写作。