任何写过一点PHP的人都知道flush() 系列函数的作用。使用chunked transfer[0]的理想使用场景是当我们有一些昂贵的东西需要渲染时,例如博客上的前三篇最近的文章。人们可能会问,为什么?
其实很简单:在一个正常的请求中,服务器会用Content-Length 头来响应,浏览器会等待整个页面下来,然后再加载资产等。
使用Transfer-Encoding: chunked 标头,服务器会将渲染好的页面的各个部分送回给浏览器,因此在Rails中,它从布局开始,然后发送<head> 部分,包括js和css等资产。
很明显,这有助于在客户端渲染页面:得到包含<head> 和资产的第一个块,立即开始加载资产,同时等待其他的响应。当然,现在的浏览器包括很多微优化,可能已经做了类似的事情,但这仍然是一个好的做法。
在实现上,你只需要在你的控制器方法中添加类似于.NET的东西:
class YourController < ApplicationController
def index
@articles = Article.most_recent
render stream: true
end
# other controller logic
end
最新版本的Unicorn(4.x)默认[1]支持分块响应。你也可以在你的unicorn_config.rb 中加入类似的内容。
# :tcp_nopush This prevents partial TCP frames from being sent out
在Rails中使用流媒体时,由于模板渲染顺序的颠倒,我们也有一些怪癖[2]。
当流媒体时,渲染是自上而下的,而不是自内而外的。Rails从布局开始,而模板是在后面渲染的,当其产量达到时。
tl;dr: 当你有多个调用content_for 时,使用provide 而不是content_for ,否则会破坏流媒体的目的和/或它会连接content_for 的值。
在NewRelic代理和Heroku中还有一个 "小 "问题:你需要禁用浏览器工具,否则你会得到一个空白的页面[3],幸好这个修复是相当琐碎的:
# :tcp_nopush This prevents partial TCP frames from being sent out
# :tcp_nodelay Disables Nagle’s algorithm on TCP sockets if true.
port = ENV["PORT"].to_i || 3000
# the ENV["PORT"] is a Heroku environment variable
listen port, tcp_nopush: false, tcp_nodelay: true
还有ActionController::Live ,可以用来创建一个简单的Rails 4聊天应用程序[4][5]。