【问题标题】:readable.on('end',...) is never firedreadable.on('end',...) 永远不会被解雇
【发布时间】:2016-04-05 01:14:52
【问题描述】:

我正在尝试将一些音频流式传输到我的服务器,然后将其流式传输到用户指定的服务,用户将向我提供someHostName,它有时不支持该类型的请求。

我的问题是,当它发生时,clientRequest.on('end',..) 永远不会被解雇,我认为这是因为它被传送到 someHostReq,当 someHostName 是“错误”时,它会变得一团糟。

我的问题是:

即使流 clientRequest 管道出现问题,我仍然可以触发 clientRequest.on('end',..) 吗?

如果不是:我如何检测到someHostReq“立即”发生了问题? someHostReq.on('error') 不会启动,除非经过一段时间。

代码:

    someHostName = 'somexample.com'

    function checkIfPaused(request){//every 1 second check .isPaused
        console.log(request.isPaused()+'>>>>');
        setTimeout(function(){checkIfPaused(request)},1000);
    }

    router.post('/', function (clientRequest, clientResponse) {
        clientRequest.on('data', function (chunk) {
            console.log('pushing data');
        });

        clientRequest.on('end', function () {//when done streaming audio
            console.log('im at the end');
        }); //end clientRequest.on('end',)

        options = {
            hostname: someHostName, method: 'POST', headers: {'Transfer-Encoding': 'chunked'}
        };

        var someHostReq = http.request(options, function(res){
            var data = ''
            someHostReq.on('data',function(chunk){data+=chunk;});
            someHostReq.on('end',function(){
                console.log('someHostReq.end is called');
            });
        });
        clientRequest.pipe(someHostReq);
        checkIfPaused(clientRequest);
    });

输出:

如果主机名正确:

    pushing data
    .
    .
    pushing data
    false>>>
    pushing data
    .
    .
    pushing data
    pushing data
    false>>>
    pushing data
    .
    .
    pushing data
    console.log('im at the end');
    true>>>
    //continues to be true, that's fine

如果主机名错误:

    pushing data
    .
    .
    pushing data
    false>>>>
    pushing data
    .
    .
    pushing data
    pushing data
    false>>>>
    pushing data
    .
    .
    pushing data
    true>>>>
    true>>>>
    true>>>>
    //it stays true and clientRequest.on('end') is never called
    //even tho the client is still streaming data, no more "pushing data" appears

如果你认为我的问题是重复的:

您可以通过执行以下任一操作切换到流动模式:

添加一个“数据”事件处理程序来监听数据。

调用 resume() 方法以显式打开流。

调用 pipe() 方法将数据发送到 Writable。

来源:https://nodejs.org/api/stream.html#stream_class_stream_readable

【问题讨论】:

  • 您是否尝试改为收听close
  • 什么是lisyen关闭线程?
  • 流有close事件以及end事件,详见here
  • 刚试过,close 主机名错误时不会触发事件

标签: node.js stream


【解决方案1】:

错误主机名的行为似乎与缓冲区有些问题,如果目标流缓冲区已满(因为 someHost 没有收到发送的数据块)管道将不会继续读取源流,因为管道自动管理流量。由于管道没有读取原始流,因此您永远不会到达“结束”事件。

无论如何我仍然可以让 clientRequest.on('end',..) 被解雇 即使流 clientRequest 管道有问题 吗?

除非完全消耗数据,否则不会触发“结束”事件。要在暂停的流中触发“结束”,您需要调用 resume()(首先从错误的主机名解除管道,否则您将再次陷入缓冲区卡住)再次将流设置为 flowMode 或将read() 设置为结束。

但是如何检测我何时应该执行上述任何操作?

someHostReq.on('error') 是自然的地方,但如果启动时间太长:

首先尝试设置一个低超时请求(少于 someHostReq.on('error') 触发所需的时间,这对您来说似乎太多时间)request.setTimeout(timeout[, callback]) 并检查它是否在正确的主机名时不会失败。如果可行,只需使用callbacktimeout 事件来检测服务器何时超时并​​使用上述技术之一到达终点。

如果超时解决方案失败或不符合您的要求,您必须使用clientRequest.on('data')clientRequest.on('end') 和/或clienteRequest.isPaused 中的标志来猜测您何时被缓冲区卡住。当您认为自己被卡住时,只需应用上述技术之一即可到达流的末尾。幸运的是,与等待 someHostReq.on('error') 相比,检测缓冲区卡住所需的时间更少(可能两个 request.isPaused() = true 没有到达 'data' 事件足以确定您是否卡住了)。

我如何检测到 someHostReq 发生了问题 “立即地”? someHostReq.on('error') 不会启动,除非之后 一段时间。

错误触发时触发。您不能“立即”检测到它。 ¿ 为什么不在管道流之前发送证明信标请求以检查支持?某种:

"检查用户指定的服务..." If OK -> 将用户请求流传送到服务OR FAIL -> 通知用户错误的服务。

【讨论】:

    猜你喜欢
    • 2013-08-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-07-11
    • 2018-01-07
    • 1970-01-01
    相关资源
    最近更新 更多