2011-03-20 91 views
35

從Net :: HTTP中拯救異常的最佳方式是什麼?從Net :: HTTP處理異常的最佳方式是什麼?

拋出的異常在Ruby的socket.c中描述,如Errno::ETIMEDOUTErrno::ECONNRESETErrno::ECONNREFUSED。該基類所有這些是SystemCallError,但感覺奇怪,因爲SystemCallError似乎到目前爲止作出的HTTP通話中移除寫類似下面的代碼:

begin 
    response = Net::HTTP.get_response(uri) 
    response.code == "200" 
rescue SystemCallError 
    false 
end 

難道僅僅是我嗎?有沒有更好的方式來解決這個問題,除了修復Net::HTTP來處理Errno異常,可能會彈出並將它們封裝在父代HttpRequestException中?

+2

謝謝大家!我最終打包了一個Ruby Gem形式的答案,我可以在將來處理這種情況:net_http_exception_fix [https://github.com/edward/net_http_exception_fix] – 2011-03-21 01:10:21

+1

正確的鏈接:https://github.com/edward/net_http_exception_fix(Edward的評論在URL中插入一個額外的「]」)。 – myhd 2012-12-20 21:48:22

+1

我已經寫了另一個庫,以不同的方式解決相同的問題:http://github.com/barsoom/net_http_timeout_errors – 2013-01-26 21:41:34

回答

34

我同意,處理所有潛在的例外是絕對痛苦的。看看this來看一個例子:

使用Net::HTTP會很痛苦。它有大約40種不同的方式可以完成任何一項任務,並且可以拋出50個左右的例外。

只爲谷歌的喜愛,這裏就是我已經得到了捕獲任何異常的「正道」 淨:: HTTP可以在你扔:

begin 
    response = Net::HTTP.post_form(...) # or any Net::HTTP call 
rescue Timeout::Error, Errno::EINVAL, Errno::ECONNRESET, EOFError, 
     Net::HTTPBadResponse, Net::HTTPHeaderSyntaxError, Net::ProtocolError => e 
    ... 
end 

爲什麼不rescue Exception => e?這是一個不好的習慣,因爲 它隱藏了您的實際代碼中的任何問題(如SyntaxErrors,whiny nils等)。當然,如果可能的 錯誤有一個共同的祖先,這將會更容易。

我在處理Net :: HTTP時遇到的問題讓我懷疑是否值得編寫一個新的HTTP客戶端庫。 一個在測試中更容易模擬出來,並沒有所有這些醜陋的小方面。

我所做的,見過很多人做的,是從網:: HTTP搬走,搬到第三方HTTP庫,如:

httpartyfaraday

+4

或者Ruby自己的[Open-URI](http://rubydoc.info/stdlib/open-uri/1.9.2/frames)或[HTTPClient](http://rubydoc.info/gems/httpclient/2.1.6.1 /幀)或[Typhoeus](https://github.com/dbalatero/typhoeus)。 Open-URI是用於快速任務的更簡單的界面。 HTTPClient和Typhoeus是工業強度,處理線程和各種其他繁重工作。 – 2011-03-20 19:46:28

+0

'HTTPClient'很熱!我想我最終會在未來使用它。感謝您的參考。 – 2011-03-21 01:11:32

+0

您的Google-fu優越,我很高興登陸Tammer的工作。這正是我正在尋找的。 – 2011-03-21 01:14:27

3

你的直覺上這是正確的,對於最強大的解決方案,我可能會逐個解救每個人(或小組),並採取適當的措施,例如再次嘗試連接,或一起放棄請求。我喜歡避免使用非常高級的/通用的救援,因爲它可能會捕獲我沒有準備好或沒有預料到的異常情況。

+1

好吧,很酷 - 很高興知道我不是唯一一個:) 我最終將您的建議+ @MikeLewis打包成一個名爲net_http_exception_fix的gem – 2011-03-21 01:12:16

16

我遇到過同樣的問題,經過大量的研究,我意識到處理所有異常的最佳方式Net :: HTTP方法會拋出的是從StandardError中拯救。

正如Mike Lewis's answer所指出的,Tammer Saleh blog post提出從很多例外中拯救,但它仍然存在缺陷。有些例外情況他不能從中解救出來,例如Errno::EHOSTUNREACH,Errno::ECONNREFUSED,以及可能的某些socket例外情況。

所以,正如我在tenderlove's translation of an old ruby-dev thread發現,最好的解決辦法是從StandardError搶救,不幸的是:

begin 
    response = Net::HTTP.get_response(uri) 
rescue StandardError 
    false 
end 

這是可怕的,但如果你想因爲這些其他異常的系統不破,使用這種方法。

0

另一種方法是聚集在一個恆定的所有這些異常,然後再使用此常量,例如:

ALL_NET_HTTP_ERRORS = [ 
    Timeout::Error, Errno::EINVAL, Errno::ECONNRESET, EOFError, 
    Net::HTTPBadResponse, Net::HTTPHeaderSyntaxError, Net::ProtocolError 
] 

begin 
    your_http_logic() 
rescue *ALL_NET_HTTP_ERRORS 
    … 
end 

這是更易於維護和清潔。

然而,警告的話。我從上述Tammer Saleh的博客文章中複製了可能的例外列表,並且我知道他的列表不完整。例如,Net::HTTP.get(URI("wow"))增加了Errno::ECONNREFUSED,這未列出。另外,如果列表應該針對不同的Ruby版本進行修改,我不會感到驚訝。

因此,我建議大多數情況下堅持使用rescue StandardError。爲了避免捕捉太多,儘可能在開始救援結束區外移動,最好只留下一個電話給Net::HTTP方法之一。

相關問題