Action Controller Streaming
允许视图在渲染时流式传输回客户端。
默认情况下,Rails
通过首先渲染模板,然后渲染布局来渲染视图。在整个模板渲染完、所有查询完成以及布局处理完成后,响应将发送到客户端。
Streaming
通过首先渲染布局,然后在处理时渲染布局的每个部分来颠倒渲染流程。这允许 HTML 的标题(通常在布局中)非常快地流式传输回客户端,从而使 JavaScript 和样式表比平时更早加载。
一些 Rack 中间件可能无法正常工作,在流式传输时需要小心。下面将详细介绍,请参阅Streaming
处的中间件 部分。
可以轻松地将Streaming
添加到给定模板中,您只需将:stream
选项传递给render
即可。
class PostsController
def index
@posts = Post.all
render stream: true
end
end
何时使用流式传输
对于像new
或edit
这样的轻量级操作,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
的Rendering
将不起作用。
布局和模板之间的通信
在流式传输时,渲染从上到下进行,而不是从内到外。Rails
从布局开始,模板在稍后到达其yield
时渲染。
这意味着,如果您的应用程序当前依赖于模板中设置的实例变量在布局中使用,那么在您转向流式传输后它们将无法正常工作。无论您是否使用流式传输,在布局和模板之间进行通信的正确方法是使用content_for
、provide
和yield
。
举一个简单的例子,布局希望模板告诉它使用哪个标题
<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>
也就是说,在流式传输时,您需要正确检查您的模板,并选择何时使用provide
和content_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+ 兼容的服务器都支持流式传输。