ExpressJS - 管道传输到响应流不起作用。

7

我有一个基本的express应用:

var express = require('express');
var app = express();
var PORT = 3000;
var through = require('through');


function write(buf) {
    console.log('writing...');
    this.queue('okkkk');
}

function end() {
    this.queue(null);
}

var str = through(write, end);


/* routes */
app.get('/', function(req, res){
    res.send("Hello!");
})


app.post('/stream', function(req, res){
    var s = req.pipe(str).pipe(res);
    s.on('finish', function() {
       console.log('all writes are now complete.'); // printed the first time
    });
});


/* listen */
app.listen(PORT, function () {
    console.log('listening on port ' + PORT + '...');
});

当我在启动服务器后首次将一些数据发布到/stream端点时,我会得到预期的响应okkk。然而,在此之后,任何对/stream端点的请求都只是超时而不返回任何响应。
为什么会这样?这里到底发生了什么?

你正在进行请求的管道传输,但你仍然需要用响应来回答该请求,或者至少使用 res.end() 来结束它,否则它会一直保持打开状态,直到超时。 - adeneo
只有在显式调用.write()时才需要end(),但我尝试了一下,现在加上它后我得到了一个空响应。另外,如果我需要.end(),为什么第一次启动服务器后它会起作用? - Jatin
嗯,由于某种原因,响应没有完成并且保持打开状态,我不确定为什么,我从未见过有人在请求中使用管道,这可能是原因。 - adeneo
嗯,请求是一个可读流,所以我认为你肯定可以将其进行管道传输。 - Jatin
你可以将它管道化,但必须结束并发送响应并关闭所有内容,否则它会被保持在待定状态。当使用整个请求进行管道传输时,我不知道如何做到这一点,也许其他人可以提供帮助? - adeneo
是的,在第一次之后,响应流上的“完成”事件从来没有被触发。我认为这可能是因为请求上的end事件从未被调用。(然而,第一次一切都正常运行)。已编辑问题细节以反映这一点。 - Jatin
2个回答

13

我曾经遇到过同样的问题,看起来 res 没有被正确地完成。因此,我向我的流添加了一个回调函数并手动结束了 res。这解决了我的问题:

stream.on('end', () => res.end());
stream.pipe(res);

这种方法实际上破坏了我的代码,导致我得到了一个空的响应,而不是流式图像。 - yuranos
@yuranos 你用什么替换了它? - Sergio
这对我很有效。我没有@Jatin所描述的问题。我是Node.js新手,但我感觉最初的问题在于封闭和对象/函数生命周期。我的代码完全包含在一个封闭中。无论如何,为什么不链式on()而不是将其作为单独的语句? - yuranos

7
当我将req.pipe(str).pipe(res)替换为req.pipe(through(write, end)).pipe(res)时,它就起作用了。这实质上确保为每个请求创建一个新的through流实例。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接