我有两种方法,如下所示,一种尝试建立连接,如果连接失败 它引发一个异常。然后应通过另一种方法挽救该异常, 引发异常的方法调用了谁。
当前conn
方法会引发错误,破坏应用程序,并且
从未获救。我该如何挽救异常,并且可以发送
异常作为响应参数?
def conn
begin
reponse = parse_response(
conn.post(
..
).tap do |res|
unless res.status == 200
raise Error::AuthenticationError.new
end
end
)
..
end
end
def parse_response(response)
body =
begin
JSON.parse(response.body)
rescue JSON::ParseError
end
rescue Error::AuthenticationError => e
LOGGER.error e
end
end
答案 0 :(得分:2)
发生这种情况是因为您的代码的这一部分在parse_respose
方法之前执行,就像它是这样写的::
def conn
begin
response = conn.post(
..
).tap do |res|
unless res.status == 200
raise Error::AuthenticationError.new
end
end
parse_response(response)
end
end
您可以将救援块移至conn
方法:
def conn
begin
reponse = parse_response(
conn.post(
..
).tap do |res|
unless res.status == 200
raise Error::AuthenticationError.new
end
end
)
..
rescue Error::AuthenticationError => e
LOGGER.error e
end
end
def parse_response(response)
body =
begin
JSON.parse(response.body)
rescue JSON::ParseError
end
end
您可以将conn.post
作为块传递给parse_response
方法,也可以创建Proc
或lambda
对象并将其作为参数传递。但是我相信最好在Error::AuthenticationError
方法中处理conn
。
答案 1 :(得分:2)
您可以通过一些重构来传递异常,但是我这里采用的方法是将传递异常作为 expected 的反模式(但不一定是 desirable >)结果。如果您确实需要传递异常的开销,则其他答案可能会为您提供有关如何通过闭包或重构调用堆栈的建议。
当然有传递异常的方法,但是这里存在一个更大的问题,那就是使用异常来处理非异常用例。例外应该是... exception 。返回非200状态代码的HTTP调用通常不是完全意外的结果。实际上,您的代码专门检查这种情况,因此它实际上是应用程序中的预期代码路径。
但是,请注意,检查“ not 200 OK”与显式检查“ 401 Unauthorized”并不完全相同。在这种情况下,与引发或绕过异常相比,按预期方式处理通常比预期的条件更快和更少出错。
一种方法(但不一定是唯一的方法)是重构您的应用程序,以明智地处理不同的预期结果。例如:
def conn
response = conn.post
# Pass through 200; handle everything else.
case response.status
when 200
when 401 then handle_auth_error(response)
when 403 then handle_forbidden_error(response)
else raise "unexpected HTTP status code: #{response.status}"
end
parse_response(response)
end
这样做的目的不在于将逻辑嵌入到#conn中。可能值得将其提取为另一种方法。关键是您应该为正在运行的应用程序无法处理的意外/未捕获的错误留下异常。
在此示例中,我们仅在未预料到的状态代码上引发异常。这将导致更简单的解决方案,并可能会带来更强大的应用程序。