如何引发异常,将其作为参数发送到另一个方法,并在另一个方法中挽救异常?

时间:2020-01-10 13:50:03

标签: ruby

我有两种方法,如下所示,一种尝试建立连接,如果连接失败 它引发一个异常。然后应通过另一种方法挽救该异常, 引发异常的方法调用了谁。

当前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

2 个答案:

答案 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方法,也可以创建Proclambda对象并将其作为参数传递。但是我相信最好在Error::AuthenticationError方法中处理conn

答案 1 :(得分:2)

TL; DR

您可以通过一些重构来传递异常,但是我这里采用的方法是将传递异常作为 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中。可能值得将其提取为另一种方法。关键是您应该为正在运行的应用程序无法处理的意外/未捕获的错误留下异常。

在此示例中,我们仅在未预料到的状态代码上引发异常。这将导致更简单的解决方案,并可能会带来更强大的应用程序。

相关问题