跳至内容 跳至搜索

Action Controller Streaming

允许视图在渲染时流式传输回客户端。

默认情况下,Rails 通过首先渲染模板,然后渲染布局来渲染视图。在整个模板渲染完、所有查询完成以及布局处理完成后,响应将发送到客户端。

Streaming 通过首先渲染布局,然后在处理时渲染布局的每个部分来颠倒渲染流程。这允许 HTML 的标题(通常在布局中)非常快地流式传输回客户端,从而使 JavaScript 和样式表比平时更早加载。

一些 Rack 中间件可能无法正常工作,在流式传输时需要小心。下面将详细介绍,请参阅Streaming 处的中间件 部分。

可以轻松地将Streaming 添加到给定模板中,您只需将:stream 选项传递给render 即可。

class PostsController
  def index
    @posts = Post.all
    render stream: true
  end
end

何时使用流式传输

对于像newedit 这样的轻量级操作,Streaming 可能被认为过于复杂。流式传输的真正好处在于那些执行大量数据库查询的昂贵操作。

在这样的操作中,您希望尽可能延迟查询的执行。例如,想象一下以下dashboard 操作

def dashboard
  @posts = Post.all
  @pages = Page.all
  @articles = Article.all
end

这里的大部分查询都发生在控制器中。为了从流式传输中获益,您需要将其重写为

def dashboard
  # Allow lazy execution of the queries
  @posts = Post.all
  @pages = Page.all
  @articles = Article.all
  render stream: true
end

请注意,:stream 仅适用于模板。使用:stream :json:xmlRendering 将不起作用。

布局和模板之间的通信

在流式传输时,渲染从上到下进行,而不是从内到外。Rails 从布局开始,模板在稍后到达其yield 时渲染。

这意味着,如果您的应用程序当前依赖于模板中设置的实例变量在布局中使用,那么在您转向流式传输后它们将无法正常工作。无论您是否使用流式传输,在布局和模板之间进行通信的正确方法是使用content_forprovideyield

举一个简单的例子,布局希望模板告诉它使用哪个标题

<html>
  <head><title><%= yield :title %></title></head>
  <body><%= yield %></body>
</html>

您将在模板中使用content_for 来指定标题

<%= content_for :title, "Main" %>
Hello

最终结果将是

<html>
  <head><title>Main</title></head>
  <body>Hello</body>
</html>

但是,如果content_for 被多次调用,最终结果将包含所有调用的拼接。例如,如果我们有以下模板

<%= content_for :title, "Main" %>
Hello
<%= content_for :title, " page" %>

最终结果将是

<html>
  <head><title>Main page</title></head>
  <body>Hello</body>
</html>

这意味着,如果您在布局中使用yield :title 并且想要使用流式传输,您将不得不先渲染整个模板(并最终触发所有查询),然后再流式传输标题和所有资产,这会违背流式传输的目的。或者,您可以使用一个名为provide 的辅助方法,它与content_for 功能相同,但会告诉布局停止搜索其他条目并继续渲染。

例如,上面使用provide 的模板将是

<%= provide :title, "Main" %>
Hello
<%= content_for :title, " page" %>

结果将是

<html>
  <head><title>Main</title></head>
  <body>Hello</body>
</html>

也就是说,在流式传输时,您需要正确检查您的模板,并选择何时使用providecontent_for

有关更多信息,请参阅ActionView::Helpers::CaptureHelper

标头、cookie、会话和闪存

在流式传输时,HTTP 标头将在渲染第一行之前发送到客户端。这意味着,在模板开始渲染后修改标头、cookie、会话或闪存不会传播到客户端。

中间件

需要操作主体 的中间件将无法与流式传输一起使用。您应该在开发或生产环境中流式传输时禁用这些中间件。例如,Rack::Bug 在流式传输时无法正常工作,因为它需要在 HTML 主体中注入内容。

此外,Rack::Cache 无法与流式传输一起使用,因为它尚不支持流式传输主体。在流式传输时,Cache-Control 会自动设置为“no-cache”。

错误

在流式传输时,异常变得更加复杂。这是因为模板的一部分已经渲染并流式传输到客户端,使其无法渲染整个异常页面。

目前,在开发或生产环境中发生异常时,Rails 会自动流式传输到客户端

"><script>window.location = "/500.html"</script></html>

前两个字符(">)是必需的,以防异常发生在渲染给定标签的属性时。您可以在日志记录器中检查异常的实际原因。

Web 服务器支持

与 Rack 3+ 兼容的服务器都支持流式传输。