【问题标题】:streaming html from webrick?从 webrick 流式传输 html?
【发布时间】:2009-04-19 13:46:32
【问题描述】:

有没有人尝试过从 webrick 流式传输 html/文本/内容?我尝试将 IO 分配给响应正文,但 webrick 正在等待流首先关闭。

【问题讨论】:

    标签: ruby streaming webrick


    【解决方案1】:

    偶然发现此链接 (http://redmine.ruby-lang.org/attachments/download/161),其中包含 webrick 补丁

    # Copyright (C) 2008 Brian Candler, released under Ruby Licence.
    #
    # A collection of small monkey-patches to webrick.
    
    require 'webrick'
    
    module WEBrick
    
      class HTTPRequest
        # Generate HTTP/1.1 100 continue response. See
        # http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-core/18459
        def continue
          if self['expect'] == '100-continue' && @config[:HTTPVersion] >= "1.1"
            @socket.write "HTTP/#{@config[:HTTPVersion]} 100 continue\r\n\r\n"
            @header.delete('expect')
          end
        end
      end
    
      class HTTPResponse
        alias :orig_setup_header :setup_header
        # Correct termination of streamed HTTP/1.1 responses. See
        # http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-core/18454 and
        # http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-core/18565
        def setup_header
          orig_setup_header
          unless chunked? || @header['content-length']
            @header['connection'] = "close"
            @keep_alive = false
          end
        end
    
        # Allow streaming of zipfile entry. See
        # http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-core/18460
        def send_body(socket)
          if @body.respond_to?(:read) then send_body_io(socket)
          elsif @body.respond_to?(:call) then send_body_proc(socket)
          else send_body_string(socket)
          end
        end
    
        # If the response body is a proc, then we invoke it and pass in
        # an object which supports "write" and "<<" methods. This allows
        # arbitary output streaming.
        def send_body_proc(socket)
          if @request_method == "HEAD"
            # do nothing
          elsif chunked?
            @body.call(ChunkedWrapper.new(socket, self))
            _write_data(socket, "0#{CRLF}#{CRLF}")
          else
            size = @header['content-length'].to_i
            @body.call(socket)   # TODO: StreamWrapper which supports offset, size
            @sent_size = size
          end
        end
    
        class ChunkedWrapper
          def initialize(socket, resp)
            @socket = socket
            @resp = resp
          end
          def write(buf)
            return if buf.empty?
            data = ""
            data << format("%x", buf.size) << CRLF
            data << buf << CRLF
            socket = @socket
            @resp.instance_eval {
              _write_data(socket, data)
              @sent_size += buf.size
            }
          end
          alias :<< :write
        end
      end
    end
    
    if RUBY_VERSION < "1.9"
      old_verbose, $VERBOSE = $VERBOSE, nil
      # Increase from default of 4K for efficiency, similar to
      # http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/branches/ruby_1_8/lib/net/protocol.rb?r1=11708&r2=12092
      # In trunk the default is 64K and can be adjusted using :InputBufferSize,
      # :OutputBufferSize
      WEBrick::HTTPRequest::BUFSIZE = 16384
      WEBrick::HTTPResponse::BUFSIZE = 16384
      $VERBOSE = old_verbose
    end
    

    使用简单地传递一个过程作为响应主体,就像这样

    res.body = proc { |w|
      10.times do
        w << Time.now.to_s
        sleep(1)
      end
    }
    

    哇!

    【讨论】:

      【解决方案2】:

      我建议不要将 WEBrick 用于任何事情,它是垃圾。我会说试试 Mongrel。

      我知道这不是你的问题,只是一些友好的建议。

      【讨论】:

      • 嘿嘿嘿,这和你的“它是垃圾”一样真实 :) 真的取决于你的需求。
      • 其实这是一个好点。您有什么特别需要 WEBrick 的需求??
      • 不要/特别/使用它们中的任何一个。使用 Rack ;-) 也就是说,安装了 Mongrel 的 Rack 0.9 及以上版本现在已经开箱即用了 :)
      猜你喜欢
      • 2021-06-10
      • 2010-12-28
      • 1970-01-01
      • 2012-04-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-01-07
      • 2013-05-11
      相关资源
      最近更新 更多