【问题标题】:How to flush current output in RApache?如何刷新 RApache 中的当前输出?
【发布时间】:2013-05-02 04:20:49
【问题描述】:

我正在使用 RApache 作为 SSE(服务器发送事件)和类似的(长轮询、彗星等)后端进行测试。我似乎被困在如何刷新我的输出上。有可能吗?

这是我的测试 R 脚本:

setContentType("text/plain")

repeat{
    cat(format(Sys.time()),"\n")
    #sendBin(paste(format(Sys.time()),"\n"))
    flush(stdout())
    Sys.sleep(1)
    }

我的 Rapache.conf 条目是:

<Location /rtest/sse>
    Options -MultiViews
    SetHandler r-handler
    RFileHandler /var/www/local/rtest/sse.r
</Location>

我使用 wget 或 curl 对其进行测试:

wget -O - http://localhost/rtest/sse
curl http://localhost/rtest/sse

两者都坐在那里,意味着什么都没有发送。

使用sendBin() 没有改变,使用flush() 也没有。

如果我将repeat 更改为for(i in 1:5),那么它会在那里停留 5 秒,然后显示 5 个时间戳(间隔 1 秒)。所以,我相信其他一切都运行良好,这纯粹是一个缓冲问题。

更新: 5 个月后以全新的眼光看待这个问题,我想我可以更清楚地描述问题:问题是 RApache 似乎正在缓冲所有输出,并且不发送任何内容直到 R 脚本退出。为了对流式传输有用,每次调用 flush() 时,即当 R 脚本仍在运行时,它必须将数据从 Apache 发送到客户端。 所以,我的问题是:有没有办法让 RApache 表现得像那样?

更新 2 我尝试在 flush(stdout()) 之前或之后添加 flush.console() 但没有区别。我还在顶部尝试了setStatus(status=200L)。我在脚本顶部尝试了SERVER$no_cache=T;SERVER$no_local_copy=T;。再次没有任何区别。 (是的,这些应该都没有帮助,但尝试永远不会有坏处!)

这里是 PHP 在作为 Apache 模块运行时如何实现刷新的链接: http://git.php.net/?p=php-src.git;a=blob;f=sapi/apache2handler/sapi_apache2.c#l290 我认为关键是有一个电话到ap_rflush(r)。我猜 RApache 没有拨打ap_rflush() 电话。

【问题讨论】:

  • 感谢您的更新。你能发布调用.rhtml文件的javascript吗?
  • @Michele 没有rhtml页面,我是用wget和curl测试的,如上图。 (我不希望浏览器混淆这个问题。)
  • 哦,我明白了。对不起,我想帮忙,但我可能会让你感到困惑......
  • 大家好,在link 的下一条关于flush.console 的消息中,Simon Urbanek 提到了一些关于TERM=dumb 的信息。我不知道这是否有帮助。

标签: rapache


【解决方案1】:

您传递了错误的 MIME 类型。尝试改变

setContentType("text/event-stream")

编辑1:

这是我在下面的评论中提到的尝试(仍然不成功)在Rook 中实施 SSE。

<%
  res$header('Content-Type', 'text/event-stream')
  res$header('Cache-Control', 'no-cache')
  res$header('Connection', 'keep-alive')
  A <- 1

  sendMessage <- function(){
    while(A<=4){
      cat("id: ", Sys.time(), "\n", "data: hello\n\n", sep="")
      A <- A+1
      flush(stdout())
      Sys.sleep(1)
    }
  }

-%>

<% sendMessage() %>

while 循环条件应该始终为TRUE,但我遇到了同样的问题,所以我不得不做一个有限循环...

好消息是我确实有数据到达浏览器。我可以通过在开发人员工具中查看 Response Header 部分中的 Content-Length 来判断。上面的代码显示为 114,然后您将“Hello!”中的“Hello”改为“Hello”。它会说 118。

js 代码是:(你也需要 JQuery)

$(document).ready(function(){

  $("button").click(function(){

    var source = new EventSource("../R/sse.Rhtml");

    source.onopen = function(event){
      console.log("readyState: " + source.readyState);
    }

    source.onmessage = function(event){
      $("#div").append(event.data);
    };

    source.onerror = function(event){
      console.log(event);
    };

  });


});

所以,本质上

1) 连接打开(readyState 1)

2) 缓冲仍然存在

3) 数据(缓冲后)到达浏览器,但在正确接收时发生错误。

EIDT2:

有趣的是,在 brew() 上面的 .Rhtml 文件中,输出没有被缓冲。 Web 服务器(R 内部和 Apache)中必须有一个配置来缓冲数据流。

附带说明,flush 甚至不需要,cat 的输出默认为stout()。所以选项是:

  1. Web 服务器配置
  2. PHP ob_flush(); 的 R 等效项,在我见过的任何 PHP 实现中总是使用它。 this 是例子

【讨论】:

  • 谢谢米歇尔。 text/event-stream 用于 SSE,text/plain 用于所有备用选项。由于我正在从 wget 和 curl 进行测试,并且不发送 SSE 格式的输出,因此 mime 类型无论如何都无关紧要。问题是整个响应都被缓冲了:在 R 脚本退出之前它不会发送任何内容。
  • @DarrenCook 我明白了。很抱歉索赔。也许我又错了(我刚刚开始将Rook 推向极限:))但是你能试试没有repeat 会发生什么吗?
  • 你好@Michele,没有repeat 它可以正常工作(参见关于使用for(i in 1:5) 的部分:它会在那里停留5 秒,然后吐出所有数据)。
  • @Darren 我明白了,但我的意思是没有repeatfor。我正在使用 Rook 测试一些 SSE,并且我设法通过 catflush 获得了连续的数据流。
  • 很高兴看到您的示例代码/设置。 (我正在写一本关于 SSE 的书,并想添加一个关于如何将它与 R 一起使用的简短部分,但到目前为止还不能让它工作!)我不依赖于 Apache 或 RApache。 Rook 是独立的 http 服务器吗?
猜你喜欢
  • 2018-09-25
  • 2017-09-26
  • 2015-12-01
  • 2021-04-12
  • 1970-01-01
  • 2013-07-21
  • 1970-01-01
  • 2013-09-10
  • 2022-01-25
相关资源
最近更新 更多