我最近发现了 Rails Streaming,在阅读了各种文档后,我尝试将它添加到我的一个控制器中,如下所示:
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)似乎有类似的问题,但尚未成功解决:
可能对我有用的东西对他们也有用。
Streaming 真的可以帮助我们的应用程序,如果我能让它正常工作,但我什至无法让 demo 流媒体应用程序正确运行!我怀疑这可能与我的开发环境有关,但是当我将我的应用程序部署到 Heroku 时问题仍然存在,而且我没有想法。任何帮助将不胜感激 。 . .
谢谢!
我试过你提到的演示回购,行为符合预期。在您展示的示例中,它将停止流式传输模板,然后等待它在 5 秒后完全呈现并发送其余部分。如果你使用卷曲:
# 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 秒发送一次部分内容。
使用模板进行流式传输的主要目标是让浏览器在接收其余内容之前接收标题,这样可以节省加载资产的时间。如文档中所述.
Streaming 通过首先渲染布局并在处理布局的每个部分时流式传输来反转渲染流程。这允许 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.
Puma 的一位维护者发现了一个 Rails 错误:#23828“ActionController::Streaming doesn't stream”。该错误自 2016 年以来一直存在,并在 2023 年 3 月仍然存在。根据我的阅读,该功能目前无法使用。这里接受的答案使用 ActionController::Live 并且可能仍然可行。
根据那里的评论,它可能会在 rails 切换到机架 3 后得到修复。这个过程现在似乎正在进行中。
为在此期间尝试使用“stream: true”的任何人发布此信息。