强力调用一个片状API:使用Net :: HTTP进行适当的错误处理

dre*_*ves 10 ruby api web-services http

我把它一起作为一种表面上看起来很健壮的方式来调用一个不稳定的web服务,它会给出超时和偶尔的名称解析或套接字错误等等.我想我会把它放在这里以防它有用,或者更有可能被告知更好的方法来做到这一点.

require 'net/http'

retries = 5
begin
  url = URI.parse('http://api.flakywebservice.com')
  http = Net::HTTP.new(url.host, url.port)
  http.read_timeout = 600  # be very patient
  res = nil
  http.start{|http|
    req = Net::HTTP::Post.new(url.path)
    req.set_form_data(params)  # send a hash of the POST parameters
    res = http.request(req)
  }
rescue Exception   # should really list all the possible http exceptions
  sleep 3
  retry if (retries -= 1) > 0
end

# finally, do something with res.body, like JSON.parse(res.body)
Run Code Online (Sandbox Code Playgroud)

这个问题的核心是:在打电话给这样的网络服务时,我应该寻找所有例外情况?这是尝试收集所有这些,但似乎必须有一个比这更好的方法:http: //tammersaleh.com/posts/rescuing-net-http-exceptions

Joh*_*hir 7

例外是有意义的,并Net::HTTP为不同类型的案例提供特定的例外.因此,如果您想以特定方式处理它们,您可以.

那篇文章说,处理这些特定的例外比处理更好/更安全rescue Exception,这是非常正确的.但是,rescue Exceptionrescue本身是不同的,相当于rescue StandardError,如果你没有理由做任何其他事情,那么你应该默认做这件事.

抢救顶级Exception将拯救整个执行堆栈中可能发生的任何事情,包括ruby耗尽磁盘或内存的某些部分或者有一些模糊的系统相关IO问题.

因此,就"拯救什么"而言,如果将代码更改为,通常会更好rescue.你会抓住你想要的一切,而不是你想要的任何东西.但是,在这种特殊情况下,那个人的列表中只有一个例外,它不是StandardError的后代:

def parents(obj)
  ( (obj.superclass ? parents(obj.superclass) : []) << obj)
end

[Timeout::Error, Errno::EINVAL, Errno::ECONNRESET, EOFError, Net::HTTPBadResponse,
  Net::HTTPHeaderSyntaxError, Net::ProtocolError].inject([]) do |a,c|
  parents(c).include?(StandardError) ? a : a << c
end
# Timeout::Error < Interrupt

parents(Timeout::Error)
# [ Object, Exception < Object, SignalException < Exception,
#   Interrupt < SignalException, Timeout::Error < Interrupt ]
Run Code Online (Sandbox Code Playgroud)

因此,您可以将代码更改为,rescue StandardError, Timeout::Error => e并且您将涵盖该文章中提到的所有案例,以及更多内容,但不包括您不想涵盖的内容.(这=> e不是必需的,但更多内容如下).

现在,就你处理flakey API的实际技术而言 - 问题是,你正在处理的API有什么问题?格式错误的回复?没有回复?问题出在HTTP级别或您正在获取的数据中吗?

也许你还不知道,或者你还没关心,但是你知道重试往往会完成工作.在这种情况下,我至少建议记录异常.Hoptoad有一个免费的计划,并且有某种类似的东西Hoptoad.notify(e)- 我不记得那是否是确切的调用.或者您可以使用e.message和发送电子邮件或登录e.stacktrace.