从Net :: HTTP处理异常的最佳方法是什么?

Edw*_*ing 47 ruby

从Net :: HTTP中拯救异常的最佳方法是什么?

抛出的异常的Ruby的描述socket.c,如Errno::ETIMEDOUT,Errno::ECONNRESETErrno::ECONNREFUSED.所有这些的基类是SystemCallError,但编写如下代码感觉很奇怪,因为SystemCallError似乎远远没有HTTP打电话:

begin
  response = Net::HTTP.get_response(uri)
  response.code == "200"
rescue SystemCallError
  false
end
Run Code Online (Sandbox Code Playgroud)

只有我吗?除了修复Net::HTTP以处理Errno可能弹出并将其封装在父级中的异常之外,是否有更好的方法来处理此问题HttpRequestException

Mik*_*wis 45

我同意处理所有潜在的例外是一种绝对的痛苦.看看这个看一个例子:

与之合作Net::HTTP可能会带来痛苦.它有大约40种不同的方式来完成任何一项任务,并且它可以抛出大约50种异常.

只是为了谷歌的热爱,这就是我为了捕捉Net :: 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
Run Code Online (Sandbox Code Playgroud)

为什么不rescue Exception => e呢?这是一个不好的习惯,因为它隐藏了实际代码中的任何问题(如SyntaxErrors,whiny nils等).当然,如果可能的错误有一个共同的祖先,这将更容易.

我在处理Net :: HTTP时遇到的问题让我想知道编写新的HTTP客户端库是否值得.一个更容易在测试中嘲笑,并没有所有这些丑陋的小方面.

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

httparty法拉第

  • 或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是工业强度,处理线程和各种其他繁重的工作. (4认同)
  • `Errno :: ECONNREFUSED`值得包括.请参阅[here](http://ruby-doc.org/stdlib-1.9.2/libdoc/socket/rdoc/Socket.html#method-i-connect-label-Unix-based+Exceptions)Unix错误列表基地系统 (4认同)

Hug*_*res 23

我遇到了同样的问题,经过大量的研究,我意识到处理Net :: HTTP方法抛出的所有异常的最佳方法是从StandardError中解救.

正如Mike Lewis的回答所指出的那样,Tammer Saleh博客文章建议从许多例外中拯救,但它仍然存在缺陷.有一些例外,他没有拯救,例如Errno::EHOSTUNREACH,Errno::ECONNREFUSED可能有一些socket例外.

因此,正如我在tenderlove中发现的旧ruby-dev线程的翻译一样,最好的解决方案是拯救StandardError,不幸的是:

begin
  response = Net::HTTP.get_response(uri)
rescue StandardError
  false
end
Run Code Online (Sandbox Code Playgroud)

这很糟糕,但如果您希望系统不会因为这些其他异常而中断,请使用此方法.

  • 请注意,这也会消除类似 VCR::Errors::UnhandledHTTPRequestError 的错误 (2认同)

ska*_*lee 7

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

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
Run Code Online (Sandbox Code Playgroud)

它更易于维护和清洁。

但是,警告的话。我已经从上述 Tammer Saleh 的博客文章中复制了可能的例外列表,我知道他的列表不完整。例如,未列出的Net::HTTP.get(URI("wow"))加薪Errno::ECONNREFUSED。此外,如果应该针对不同的 Ruby 版本修改列表,我也不会感到惊讶。

出于这个原因,我建议rescue StandardError在大多数情况下坚持。为了避免捕获太多,尽可能多地移动到 begin-rescue-end 块之外,最好只留下对其中一种Net::HTTP方法的调用。