Как вызвать исключение, отправить его в качестве параметра другому методу и спасти исключение в другом методе? - PullRequest
0 голосов
/ 10 января 2020

У меня есть два метода, как показано ниже, один пытается установить соединение, в случае неудачи возникает исключение. Затем это исключение должно быть спасено другим методом, который был вызван методом, вызвавшим исключение.

В настоящее время метод 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 ]

2 голосов
/ 10 января 2020

TL; DR

Вы можете передавать исключения с помощью некоторого рефакторинга, но я использую здесь подход к рассмотрению передачи исключений как анти-паттерна для ожидаемого (но не обязательно желательно ) результаты. Если вам действительно нужны накладные расходы для обхода исключений, другие ответы, скорее всего, дадут вам советы о том, как это сделать с помощью замыканий или рефакторинга стека вызовов.

Анализ и рекомендации

Конечно, есть способы обойти исключения, но здесь есть большая проблема, а именно использование исключения для обработки неисключительного варианта использования. Исключения должны быть ... ну, исключительные . Вызов HTTP, который возвращает код состояния, отличный от 200, обычно не является совершенно неожиданным результатом. На самом деле, ваш код специально проверяет это состояние, так что на самом деле это ожидаемый путь кода в вашем приложении.

Однако обратите внимание, что проверка «not 200 OK» не на самом деле то же самое, что явная проверка на 401 Несанкционированный. В таких случаях обработка ожидаемого условия как такового, как правило, быстрее и менее подвержена ошибкам, чем возбуждение или обход исключений.

Один из способов решения этой проблемы (но, конечно, не единственный) - это рефакторинг приложения для обработки разные ожидаемые результаты разумно. Например:

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

Смысл этого состоит не столько в встраивании logi c в #conn; безусловно, стоит извлечь его другим способом. Суть в том, что вы должны оставлять исключения для непредвиденных / необработанных ошибок , которые не могут быть обработаны в работающем приложении.

В этом примере мы создаем исключение только для кодов состояния, которые мы не ожидал. Это приводит к гораздо более простому решению и, вероятно, более надежному приложению.

2 голосов
/ 10 января 2020

Это происходит из-за того, что эта часть вашего кода выполняется до 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 метода.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...