2010-02-01 105 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