5

Rails 3.1 でユニコーンをセットアップしました。Rack::Deflater を有効にするまで、http ストリーミングは機能します。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

助けてくれてありがとう。

4

1 に答える 1

5

問題は、Rails ActionController::Streaming が Chunked::Body に直接レンダリングされることです。これは、gzip されてからチャンク化されるのではなく、Rack::Deflater ミドルウェアによってコンテンツが最初にチャンク化されてから gzip されることを意味します。

HTTP/1.1 RFC 6.2.1によると、チャンクは最後に転送にエンコードを適用する必要があります。

「チャンク」は、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 を使用している場合は、ストリーミング時にミドルウェアも無効にする必要があります。

于 2012-05-15T07:31:36.863 に答える