从Net :: HTTP中拯救异常的最佳方法是什么?
抛出的异常的Ruby的描述socket.c,如Errno::ETIMEDOUT,Errno::ECONNRESET和Errno::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可能引发的任何异常的"正确方法"所得到的:
Run Code Online (Sandbox Code Playgroud)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客户端库是否值得.一个更容易在测试中嘲笑,并没有所有这些丑陋的小方面.
我所做的,以及大多数人所做的,是从Net :: HTTP转移到第三方HTTP库,例如:
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)
这很糟糕,但如果您希望系统不会因为这些其他异常而中断,请使用此方法.
另一种方法是将所有这些异常聚合在一个常量中,然后重新使用这个常量,例如:
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方法的调用。