ruby-on-rails Rails流:“呈现流:真正的“不工作

ctrmrzij  于 2023-03-24  发布在  Ruby
关注(0)|答案(2)|浏览(147)

我最近发现了Rails流,在阅读了各种文档之后,我尝试将其添加到我的一个控制器中,如下所示:

def index
    render :stream => true
end

我的模板文件目前看起来像这样:

<%10.times do%>
  <p>
    I should get streamed ERB...
    <%sleep 0.5%>
  </p>
<%end%>

但是它不是每0.5秒显示一条消息,而是等待5秒并显示整个页面!我已经在浏览器中使用curl检查了这种行为。
我在OSX上使用unicorn,是的,我配置了unicorn.rb用于流媒体:

listen 3000, :tcp_nodelay => true, :tcp_nopush => false
worker_processes 1

如果你想看我的布局文件,它看起来像这样:

<!DOCTYPE html>
<html>
<head>
  <title>StreamingTest</title>
  <%= stylesheet_link_tag    "application" %>
  <%= javascript_include_tag "application" %>
  <%= csrf_meta_tags %>
</head>
<body>

<%= yield %>

</body>
</html>

我尝试禁用所有gem(除了rails和postgres),并将控制器、布局和模板缩减到最低限度,但没有任何成功。
我甚至下载了一个完整的流媒体演示(https://github.com/slim-template/slim-streamingtest),当我运行它时,它也没有流!(任何试图运行该演示的人请注意:我不得不改变gemfile源使用https而不是http之前,我可以“捆绑安装”,我必须“捆绑更新链轮”之前,它会运行)
我注意到其他人(使用Puma)似乎也有类似的问题,但尚未成功解决:
Rails Streaming not Streaming
也许对我有用的东西也会对他们有用。
如果我能让它正常工作的话,流媒体真的会对我们的应用程序有帮助,但是我甚至不能让 demo 流媒体应用程序正确运行!我怀疑这可能与我的开发环境有关,但是当我将应用程序部署到Heroku时,问题仍然存在,我没有办法了。任何帮助都将非常感谢。
谢谢!

wribegjk

wribegjk1#

我尝试了你提到的demo repo,它的行为和预期的一样。在示例中,它会停止流式传输模板,然后等待它在5秒后完全渲染并发送其余部分。如果你使用curl:

# curl -i http://localhost:3000

HTTP/1.1 200 OK
Date: Thu, 21 Apr 2016 17:29:00 GMT
Connection: close
Cache-Control: no-cache
Transfer-Encoding: chunked
Content-Type: text/html; charset=utf-8
X-UA-Compatible: IE=Edge
X-Runtime: 0.018132

<!DOCTYPE html>
<html>
  <head>
    <title>StreamingTest</title>
    <link href="/stylesheets/application.css" media="screen" rel="stylesheet" type="text/css" />
    <script src="/javascripts/application.js" type="text/javascript"></script>
    <meta content="authenticity_token" name="csrf-param" />

然后,它等待5秒钟,让模板完成渲染,然后发送模板。

...
  <p>
    I should get streamed...
  </p>
</body></html>

这是应该发生的。它不会每0.5秒发送一部分。
使用模板流的主要目的是让浏览器在其他内容之前接收头部,这样可以保存加载资源的时间。如in the docs所述。
流式处理通过首先渲染布局并在处理布局的每个部分时流式处理来反转渲染流。这允许HTML的头部(通常在布局中)非常快速地流式传输回客户端,从而允许JavaScript和样式表比平常更早地加载。
它不会发送部分,除非它被完全渲染。
然而,为了向您展示如何获得您所期望的那种行为,您可以像这样更改application.html.slim布局的主体:

body
    = yield
    = render 'application/other'

并创建一个名为_other.html.erb的部分,内容如下

<% sleep 1 %>
<p>Me too!</p>

现在你会在curl中看到,它呈现了布局的开始,等待index.html.erb上的呈现完成,发送它并显示在curl中,然后等待_other.html.erb部分完成呈现以结束请求主体。
您也可以直接馈送请求正文,每隔几毫秒发送一次内容,您可以执行以下操作:

def index
  headers['Cache-Control'] = 'no-cache'
  self.response_body = Enumerator.new do |yielder|
    10.times do
      yielder << "I should be streamed...\n"
      sleep 0.3
    end
  end
end

然而这并不意味着发送html,尽管你可以使用render_to_string,但你必须在代码中修改很多。
请注意,所有这些都是Rails 3.x,对于4.x,您必须使用ActionController::Live。在ActionController::Live的情况下,有关于如何在js中侦听服务器发送的事件以呈现客户端的示例,例如mini-chat

vfh0ocws

vfh0ocws2#

有一个Rails bug被Puma的一个维护者打开:#23828 "ActionController::Streaming doesn't stream"。该错误自2016年以来一直开放,并在2023年3月仍然开放。从我的阅读来看,该功能目前不可用。这里接受的答案使用ActionController::Live,并且可能仍然可行。
根据那里的评论,它可能会得到修复后,铁路切换到机架3。这一过程似乎正在进行中。
为任何试图使用“流”的人发布此内容:“真的”,在时间上。

相关问题