node.js 使用 expressjs 对客户端进行流式响应时遇到问题

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/25206141/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 17:45:17  来源:igfitidea点击:

Having trouble streaming response to client using expressjs

node.jsexpressstreaming

提问by lostintranslation

I am having a really hard time wrapping my head around how to stream data back to my client when using Nodejs/Expressjs.

在使用 Nodejs/Expressjs 时,我真的很难思考如何将数据流回我的客户端。

I am grabbing a lot of data from my database and I am doing it in chunks, I would like to stream that back to the client as I get the data such that I do not have to store the entire dataset in memory as a json object before sending it back.

我正在从我的数据库中获取大量数据,并且我正在分块进行,我想在获取数据时将其流式传输回客户端,这样我就不必将整个数据集作为 json 对象存储在内存中在寄回之前。

I would like the data to stream back as a file, ie I want the browser to ask my users what to do with the file on download. I was previously creating a file system write stream and stream the contents of my data to the file system, then when done I would send the file back to the client. I would like to eliminate the middle man (creating tmp file on file system) and just stream data to client.

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

I can call res.write("some string data"), then call res.end() when I am done. However I am not 100% sure that this is actually streaming the response to the client as I write. Seems like expressjs is storing all the data until I call end and then sending the response. Is that true?

我可以调用 res.write("some string data"),然后在完成后调用 res.end()。但是,我不能 100% 确定这实际上是在我编写时将响应流式传输到客户端。似乎 expressjs 正在存储所有数据,直到我调用 end 然后发送响应。真的吗?

What is the proper way to stream strings chunks of data to a response using expressjs?

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

采纳答案by mscdex

You can do this by setting the appropriate headers and then just writing to the response object. Example:

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

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 = /[^0-6]/.test(filename)
      ? 'attachment; filename="' + encodeURI(filename) + '"; filename*=UTF-8\'\'' + encodeURI(filename)
      : 'attachment; filename="' + filename + '"';
  }

  return ret;
}

Also, Express/node does not buffer data written to a socket unless the socket is paused (either explicitly or implicitly due to backpressure). Data buffered by node when in this paused state may or may not be combined with other data chunks that already buffered. You can check the return value of res.write()to determine if you should continue writing to the socket. If it returns false, then listen for the 'drain' event and then continue writing again.

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

回答by bencripps

The responseobject is already a writable stream. Express handles sending chunked data automatically, so you won't need to do anything extra but:

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

response.send(data)

response.send(data)

You may also want to check out the built-in pipe method, http://nodejs.org/api/stream.html#stream_event_pipe.

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