跳至内容 跳至搜索

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:xml 将不起作用。

布局和模板之间的通信

在流式传输时,渲染是从上到下进行的,而不是从内到外。 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

Headers、cookies、session 和 flash

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

中间件

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

另外,Rack::Cache 也无法与流式传输一起工作,因为它目前不支持流式响应体。在流式传输时,Cache-Control 会自动设置为“no-cache”。

错误

在流式传输方面,异常会变得稍微复杂一些。这是因为模板的一部分已经被渲染并流式传输到客户端,导致无法渲染完整的异常页面。

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

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

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

Web 服务器支持

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