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

los*_*ion 12 streaming node.js express

在使用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;
        }
    }
);
Run Code Online (Sandbox Code Playgroud)

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

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

ben*_*pps 9

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

response.send(data)

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

  • 当然,重点是如果我写一次(所有数据),res.end(数据)和数据是数百万db数据行,我的服务器上可能会耗尽内存.更好的解决方案似乎是来自数据库的块(页面)中的查询数据,并在我将它们传输到流时写入每个小块. (7认同)
  • `response.send(data)`本质上是`response.end(data)`,所以一旦你调用它,就不能再传输任何数据了. (6认同)

msc*_*dex 5

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

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;
}
Run Code Online (Sandbox Code Playgroud)

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