Ruby chunked编码客户端

时间:2012-03-23 10:15:39

标签: ruby http chunked-encoding

我正在尝试创建一个小的ruby脚本,它使用HTTP Chunked Transfer编码接收流数据。所以我在客户端结束时使用了ruby。我可以找到很多关于ruby(和rails)提供流的问题和信息,但关于使用它们并不多。也许是因为它是微不足道的,应该只是作为HTTP的低级功能。那么有人可以给我一些示例脚本吗?

我尝试了几件事。这个使用open-uri:

require 'open-uri'

streamURL = 'http://localhost/sample-stream.php'

puts "Opening"

open(streamURL) do |f| 
   puts "Opening steam " + streamURL + " (never gets here)"
   p  f.meta
   p "Content-Type: " + f.content_type
   p "last modified" + f.last_modified.to_s

   no = 1
   # print the first three lines
   f.each do |line|
      print "#{no}: #{line}"
      no += 1
      break if no > 4
   end
end

...这个使用net http:

require 'net/http'
require 'uri'

streamURL = 'http://localhost/sample-stream.php'

url = URI.parse(streamURL)
full_path = (url.query.empty?) ? url.path : "#{url.path}?#{url.query}"

the_request = Net::HTTP::Get.new(full_path, {'Transfer-Encoding' => 'chunked', 'content-type' => 'text/plain'})
#(Side question: Does it even make sense to specify 'chunked' in the request?)

puts "Opening stream " + streamURL

the_response = Net::HTTP.start(url.host, url.port) { |http|
  http.request(the_request)
}

puts the_response.body #never gets here

在这两种情况下它都不会输出任何东西,我可以在apache中看到我的PHP脚本忙着喷出越来越多的数据。我觉得很清楚这里出了什么问题。在这两种情况下,我认为我的脚本在处理它之前都在等待获得整个响应(这将永远不会发生)。

我应该提一下我的php脚本(服务器)可能有问题,但我可以看到它很好地融入了firefox。

那么有一种简单的红宝石方式来传输数据吗?或者我应该期望需要特殊的宝石/库来做到这一点? (例如,我遇到了this library

3 个答案:

答案 0 :(得分:2)

我认为以下代码应该有效。

require 'net/http'

streamURL = 'http://localhost/sample-stream.php'

uri = URI.parse(streamURL)

Net::HTTP.start(uri.host, uri.port) do |http|
  request = Net::HTTP::Get.new uri.request_uri

  http.request request do |response|
    response.read_body do |chunk|
       #We get the data here chunk-by-chunk
       puts chunk
    end
  end
end

实际上这对我的sample-stream.php不起作用,但我很幸运得到类似于这个脚本的东西,指向另一台服务器。我的工作代码更复杂,因为它还需要身份验证,但我在这里删除了一点。

指向我的测试php脚本,此代码会产生一些有用的错误消息:

`read_chunked': wrong chunk size line: (Net::HTTPBadResponse)

...这清楚地表明我在php服务器端做错了。不确定是什么问题,但这是另一个问题。

答案 1 :(得分:0)

我尝试了先前答案(Net::HTTP.startwget)中的方法,但没有得到任何输出。对我有用的是:

url = <...>
IO.popen "curl -s #{url}" do |io|
  io.sync = true
  io.each do |line|
    break if !(process_line line)
  end
end

答案 2 :(得分:-1)

调用'wget'系统命令的另一种方法。

wget_command = "wget #{streamURL} --user=myusername --password=mypassword -qO-"

puts "Opening stream: #{wget_command}"
f = open("|" + wget_command)
  while (line = f.gets)
    puts "LINE:" + line  
  end #(loops forever)
end

这看起来比使用ruby的net http更可靠,而且它肯定是更紧凑的代码。作为一个额外的好处,我可以轻松地逐行获取数据(我不得不从块读取方法中捏造的东西)不确定缺点是什么。以这种方式管道stdout数据可能效率低下。此代码也不会在没有wget命令的平台上工作(windows)但对我来说这似乎比net http好一点......

然而,三四分钟后它仍然会遇到问题。我想象这可能是因为流进来太快而某些缓冲区正在填满,或者因为这个特定的流在几分钟后减速(不要问我原因。它只是这样做)所以也许是当它最终赶上时会出现错误。