使用Rack :: Deflater时,rails中的HTTP流不能正常工作

我在rails 3.1中设置了独角兽,http流式传输工作直到我启用Rack :: Deflater。 我曾尝试使用Rack :: Chunked。 在curl中,我可以看到我在chrome中的响应,我得到以下错误:ERR_INVALID_CHUNKED_ENCODING

其他浏览器(firefox,safari)以及开发(osx)和生产(heroku)之间的结果相同。

config.ru:

require ::File.expand_path('../config/environment', __FILE__) use Rack::Chunked use Rack::Deflater run Site::Application 

unicorn.rb:

 listen 3001, :tcp_nopush => false worker_processes 1 # amount of unicorn workers to spin up timeout 30 # restarts workers that hang for 30 seconds 

控制器:

 render "someview", :stream => true 

谢谢你的帮助。

问题是Rails ActionController :: Streaming直接渲染到Chunked :: Body。 这意味着内容首先被分块,然后由Rack :: Deflater中间件进行gzip压缩,而不是gzip压缩然后分块。

根据HTTP / 1.1 RFC 6.2.1 ,chunked必须是最后应用的编码到传输。

由于“chunked”是HTTP / 1.1接收者需要理解的唯一传输编码,因此它在分隔持久连接上的消息方面起着至关重要的作用。 每当传输编码应用于请求中的有效载荷主体时,所应用的最终传输编码必须“分块”。

我通过在初始化程序中修补ActionController :: Streaming _process_options和_render_template方法来修复它,因此它不会将主体包装在Chunked :: Body中,而是让Rack :: Chunked中间件代替它。

 module GzipStreaming def _process_options(options) stream = options[:stream] # delete the option to stop original implementation options.delete(:stream) super if stream && env["HTTP_VERSION"] != "HTTP/1.0" # Same as org implmenation except don't set the transfer-encoding header # The Rack::Chunked middleware will handle it headers["Cache-Control"] ||= "no-cache" headers.delete('Content-Length') options[:stream] = stream end end def _render_template(options) if options.delete(:stream) # Just render, don't wrap in a Chunked::Body, let # Rack::Chunked middleware handle it view_renderer.render_body(view_context, options) else super end end end module ActionController class Base include GzipStreaming end end 

并将您的config.ru保留为

 require ::File.expand_path('../config/environment', __FILE__) use Rack::Chunked use Rack::Deflater run Roam7::Application 

这不是一个非常好的解决方案,它可能会破坏一些检查/修改正文的其他中间件。 如果有人有更好的解决方案,我很乐意听到。

如果您使用的是新文件,则在流式传输时也必须禁用其中间件。

Interesting Posts