【问题标题】:Net::HTTPResponse body as IONet::HTTPResponse 主体作为 IO
【发布时间】:2010-03-16 23:34:34
【问题描述】:

Net::HTTPResponse 的主体是一个类似流的对象,您可以使用 read_body 在惰性夹头中读取它的输入。在 ruby​​ 的其余部分中,steam 表示为 IO 类。是否有包装器或其他东西可以让我像使用 IO 对象一样使用 Net::HTTPResponse?

【问题讨论】:

  • 我也是。就在今天,我需要将 HTTPResponse 流式传输到 CVS::Reader。如果我得到一些实用的东西,即使丑陋,我也会发布答案。

标签: ruby http io


【解决方案1】:

使用标准 Ruby 附带的 OpenURI 库。它在底层使用 Net::Http,并提供了一个方便的 File-like 对象。

require 'open-uri'
open('http://example.com/some_file') do |f|
  f.each_line do |line|
    puts "http line: #{line}"
  end
do

【讨论】:

  • 如果 content-length 超过一定大小,这将首先写入磁盘(Tempfile),然后生成 Tempfile IO 对象。仅供参考,以防磁盘空间受到限制,或者希望在没有磁盘缓冲的情况下进行流式传输。
【解决方案2】:

如果您对使用 Threads 没问题(也许只在 MRI 中安全),我已经成功地使用了它:

# create an writable IO to write the response to 
# and a readable IO to return / yield to the caller
read_io, write_io = IO.pipe

write_io.binmode
read_io.binmode

# in a separate thread, continue adding chunks to the writable IO,
# which is connected to the readable IO we return
Thread.new do
  begin
    # pipe chunks to the write stream
    # response is the Net::HTTPSuccess object
    response.read_body { |chunk| write_io << chunk }
  ensure
    write_io.close
    Thread.current.exit
  end
end

# yield a readable stream while the thread feeds the writable
yield read_io

我们创建一个与IO.pipe 连接的读 IO 和一个写 IO。由于read_body 是一个阻塞操作,它会屈服于我们给它的块,直到整个主体完成(内存中的全部内容),我们需要在一个单独的线程中read_body。收到块后,会将它们转发到我们的write_iowrite_io 本质上是一个代理,但我们可以以一种懒惰的方式从read_io 中读取,而无需等待整个响应正文被下载。这对流解析器很有用,也许你的用例也很有用。 CSV 接受一个 IO 并且可以像这样用这个方法懒惰地解析:

CSV.new(io).to_enum

这会给你一个惰性的 csv 行枚举。

【讨论】:

    猜你喜欢
    • 2015-10-10
    • 2019-01-07
    • 1970-01-01
    • 1970-01-01
    • 2010-12-27
    • 1970-01-01
    • 2020-04-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多