ruby net/http`read_body':Net :: HTTPOK#read_body被调用两次(IOError)

Col*_*ams 3 ruby net-http

我正在使用net/http库调用read_body两次(IOError).我正在尝试下载文件并有效地使用http会话.寻求一些帮助或建议来解决我的问题.从我的调试消息中,它在我记录响应代码时出现,readbody = true.这就是为什么当我尝试以块的形式编写大文件时read_body被读取两次?

D, [2015-04-12T21:17:46.954928 #24741] DEBUG -- : #<Net::HTTPOK 200 OK readbody=true>
I, [2015-04-12T21:17:46.955060 #24741]  INFO -- : file found at http://hidden:8080/job/project/1/maven-repository/repository/org/project/service/1/service-1.zip.md5
/usr/lib/ruby/2.2.0/net/http/response.rb:195:in `read_body': Net::HTTPOK#read_body called twice (IOError)
    from ./deploy_application.rb:36:in `block in get_file'
    from ./deploy_application.rb:35:in `open'
    from ./deploy_application.rb:35:in `get_file'
    from ./deploy_application.rb:59:in `block in <main>'
    from ./deploy_application.rb:58:in `each'
    from ./deploy_application.rb:58:in `<main>'
Run Code Online (Sandbox Code Playgroud)
require 'net/http'
require 'logger'

STAMP = Time.now.utc.to_i

@log = Logger.new(STDOUT)

# project , build, service remove variables above
project = "project"
build = "1"
service = "service"
version = "1"
BASE_URI = URI("http://hidden:8080/job/#{project}/#{build}/maven-repository/repository/org/#{service}/#{version}/")

# file pattern for application is zip / jar. Hopefully the lib in the zipfile is acceptable.
# example for module download /#{service}/#{version}.zip /#{service}/#{version}.zip.md5 /#{service}/#{version}.jar /#{service}/#{version}.jar.md5

def clean_exit(code)
  # remove temp files on exit
end

def get_file(file)
  puts BASE_URI 
  uri = URI.join(BASE_URI,file)
  @log.debug(uri)

  request = Net::HTTP::Get.new uri #.request_uri
  @log.debug(request)

  response = @http.request request
  @log.debug(response)

  case response
    when Net::HTTPOK
      size = 0
      progress = 0
      total = response.header["Content-Length"].to_i
      @log.info("file found at #{uri}")

      # need to handle file open error 
      Dir.mkdir "/tmp/#{STAMP}"
      File.open "/tmp/#{STAMP}/#{file}", 'wb' do |io|
        response.read_body do |chunk|
          size += chunk.size
          new_progress = (size * 100) / total

          unless new_progress == progress
             @log.info("\rDownloading %s (%3d%%) " % [file, new_progress])
          end

          progress = new_progress
          io.write chunk
        end
      end

    when 404
      @log.error("maven repository file #{uri} not found")
      exit 4

    when 500...600
      @log.error("error getting #{uri}, server returned #{response.code}")
      exit 5

    else
      @log.error("unknown http response code #{response.code}")
  end
end

@http = Net::HTTP.new(BASE_URI.host, BASE_URI.port)
files = [ "#{service}-#{version}.zip.md5", "#{service}-#{version}.jar", "#{service}-#{version}.jar.md5" ].each do |file| #"#{service}-#{version}.zip",
  get_file(file)
end
Run Code Online (Sandbox Code Playgroud)

Chr*_*ald 5

编辑:修改后的答案!

Net::HTTP#request,当没有阻挡地召唤时,将先发制人地阅读身体.文档对此并不清楚,但它通过建议在块传递时读取正文来暗示它.

如果你想在不读取正文的情况下发出请求,你需要将一个块传递给请求调用,然后从中读取正文.也就是说,你想要这样的东西:

@http.request request do |response|
  # ...
  response.read_body do |chunk|
  # ...
  end
end
Run Code Online (Sandbox Code Playgroud)

这在实施中已经明确; Response#reading_body如果给出(来自#transport_request,从中调用#request),将首先产生对块的未读响应,然后无条件地读取主体.block参数#request使您有机会在读取正文之前拦截响应.