【问题标题】:HTTP streaming in rails not working when using Rack::Deflater使用 Rack::Deflater 时,Rails 中的 HTTP 流式传输不起作用
【发布时间】:2011-12-20 15:09:33
【问题描述】:

我已经在 rails 3.1 中设置了 unicorn,并且 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

独角兽.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

感谢您的帮助。

【问题讨论】:

    标签: ruby-on-rails rake unicorn http-streaming


    【解决方案1】:

    问题在于 Rails ActionController::Streaming 直接渲染成 Chunked::Body。这意味着内容首先被 Rack::Deflater 中间件分块然后 gzip,而不是先 gzip 然后再分块。

    根据HTTP/1.1 RFC 6.2.1,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
    

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

    如果你使用的是new relic,它的中间件也必须是disabled when streaming

    【讨论】:

      猜你喜欢
      • 2013-12-08
      • 2011-11-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-06-15
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多