2010-02-01 129 views
2

如何让Ruby的Net :: HTTP模块取消请求?如何取消Ruby Net :: HTTP请求?

以下对http.finish的调用引发错误。我得到这样的印象,即响应对象不知道连接已关闭,仍然需要更多数据。

我想避免发出HEAD请求。因此,请发出GET请求,除非内容类型为HTML,否则取消请求。

Net::HTTP.start(uri.host, uri.port) do |http| 
    http.request_get(uri.path) do |response| 
    unless response['content-type'] =~ /html/i 
     http.finish 
    end 
    end 
end 

/usr/lib/ruby/1.8/net/http.rb:2241:in `stream_check': attempt to read body out of block (IOError) 
    from /usr/lib/ruby/1.8/net/http.rb:2171:in `read_body' 
    from /usr/lib/ruby/1.8/net/http.rb:2198:in `body' 
    from /usr/lib/ruby/1.8/net/http.rb:2137:in `reading_body' 
    from /usr/lib/ruby/1.8/net/http.rb:1052:in `request' 
    from /usr/lib/ruby/1.8/net/http.rb:948:in `request_get' 
    from net.rb:9 
    from /usr/lib/ruby/1.8/net/http.rb:543:in `start' 
    from /usr/lib/ruby/1.8/net/http.rb:440:in `start' 
    from net.rb:7 

回答

-1

最后我用这个解决方案(捕获异常):

require 'net/http' 


uri = URI.parse('http://mirror.globo.com/ubuntu/releases/6.06.2/ubuntu-6.06.2-server-amd64.iso') 

begin 
    Net::HTTP.start(uri.host, uri.port) do |http| 
    http.request_get(uri.path) do |response| 
     unless response['content-type'] =~ /html/i 
     p response['content-type'] 
     p 'didnt get html, stopping transfer' 
     http.finish  
     # break 
     end 
     response.read_body do |data| 
     p 'receiving data' 
     end 
    end 
    p 'transfer succesful!' 
    end 
rescue 
    p 'rescued it' 
end 

p 'broke out of net loop' 

我也有过路边(http://curb.rubyforge.org)看看libcurl的,但它依赖于回调,而不是块,并且回调唐不传入Curl实例,因此无法像Net :: HTTP一样杀死连接。

2

重新编辑,原来的答复是在底部

我不认为你从你pastie第一代码片段被闲置。请尝试以下方法明白我的意思:


h = Net::HTTP.new uri.host,uri.port 
h.set_debug_output $stderr 
h.start do |http| 
    http.request_get(uri.path) do |response| 
    end 
end 

发生的事情是,通过发出GET,您的客户必须从插座阅读整个文档,你是否真正用它做任何事情。这只是HTTP规范的一部分。

如果您没有调用response.read_body,则会阻止您的代码将响应读入内存,但是直到从套接字读取所有数据为止,该块才会返回。调用break的块会在最后的read之前爆发,这意味着即使您决定不将响应读入内存,也会使您的代码符合HTTP。 I edited your pastie指出最终读取的位置。

你刚刚正在读取一个很大的ISO文件,所以它看起来像你闲置。

简短回答是你应该发出一个HEAD请求,如果你不打算按照HTTP规范的规定阅读整个文档。

的复杂的答案是,你可以发出部分GET如果发出一个字节的范围内指定here,但我不知道的是,红宝石HTTP客户端库支持这种操作模式。

通过调用http.finish你早关闭TCP套接字,它执行的工作尽可能把你弄出去的代码块,但在提高调用代码,因为你是“不应该”要做到这一点例外。欢迎您拨打finish,如果您愿意接受例外情况,但您对HTTP的使用不够好。

原来的答案

你不应该叫finish,该 连接将得到关闭 块退出时。文档here

异常正从 this code

抛出如果你真的想迫使插座 提前关门,正好赶上了 IO错误。

我只注意到你 初始化response到 结果调用 head的,但你再次使用它作为一个块参数是 。

只是检查内容类型 你打电话request_get, 有条件的 content_type之前。

+1

没错,但我想强制关闭连接。除非内容类型符合预期,否则我不想完成请求。我也想避免在每个url上运行一个.head请求。所以,.get,如果html继续,否则关闭连接。 – Alexandre 2010-02-01 21:50:01

+0

这就是我想要避免的。我想通知http客户端,我不想继续阅读响应主体。 – Alexandre 2010-02-01 21:57:59

+0

除非您调用response.read_body,否则它不应该完成请求。如果你不打算使用它,你应该消除头呼。 – klochner 2010-02-01 21:59:12

2

我还没有通过本地代理来运行这个程序,以便绝对确定,但速度告诉我它不会读取正文,除非它的content-type是HTML。

url = URI.parse('http://alicebobandmallory.com/') 
body="" 
res = Net::HTTP.start(url.host, url.port) {|http| 
    http.request_get(url.path) {|response| 
    break unless response['content-type'] =~ /html/i 
    response.read_body {|b| 
    body<<b 
    } 
    } 
} 
+0

“break”是一个真正的,非贫民窟,正确的答案。 – Barry 2014-10-01 02:07:48