从Net :: HTTP处理exception的最好方法是什么?

从Net :: HTTP中拯救exception的最好方法是什么?

抛出的exception在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来处理Errnoexception,可能会popup并将其封装在父HttpRequestException

我同意,处理所有可能的例外是绝对痛苦的。 看看这个例子:

使用Net::HTTP可能会很痛苦。 它有大约40种不同的方式来完成任何一项任务,大约有50个例外。

只是为了爱谷歌,这里是我的“正确的方式”捕捉networking:: HTTP可以抛出你的任何exception:

 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客户端库。 一个在testing中更容易被嘲笑,并没有所有这些丑陋的小方面。

我所做的和大多数人所看到的是从Net :: HTTP转移到第三方HTTP库,例如:

httparty和法拉第

我遇到了同样的问题,并经过大量的研究,我意识到处理所有exceptionNet :: HTTP方法会抛出的最好办法就是从StandardError中解救出来。

正如迈克·刘易斯 ( Mike Lewis)的回答所指出的 , 泰勒·萨利赫 ( Tammer Saleh)的博客文章提出了很多例外,但仍然存在缺陷。 有一些例外,他不救援,如Errno::EHOSTUNREACHErrno::ECONNREFUSED ,并可能有一些socket例外。

所以,正如我在一个ruby-dev线程的翻译中发现的 ,最好的解决办法是从StandardError拯救,不幸的是:

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

这太糟糕了,但是如果你希望你的系统不会因为这些其他exception而中断,那么就使用这种方法。

你的直觉是正确的,对于最强大的解决scheme,我可能会单独地(或以小组的forms)拯救每一个人,并采取适当的行动,例如再次尝试连接,或放弃所有请求。 我喜欢避免使用非常高级的/通用的救援,因为它可能会捕获我没有准备好或没有预料到的exception。

另一种方法是将所有这些exception集合在一个常量中,然后重新使用这个常量,例如:

 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版本,我不会感到惊讶。

出于这个原因,我build议在大多数情况下坚持rescue StandardError 。 为了避免捕捉太多,尽可能在开始 – 救援结束块之外移动,最好只留下一个对Net::HTTP方法之一的调用。