Подтвердить что ты не робот

Каков наилучший способ обработки исключений из Net:: HTTP?

Каков наилучший способ спасти исключения из Net:: HTTP?

Исключенные исключения описаны в Rubys 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

Это только я? Есть ли лучший способ справиться с этим после исправления Net::HTTP для обработки исключений Errno, которые, вероятно, будут всплывать и инкапсулировать их в родительский HttpRequestException?

4b9b3361

Ответ 1

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

Работа с Net::HTTP может быть болью. Он получил около 40 различных способов для выполнения одной задачи и около 50 исключений, которые она может выполнить.

Просто для любви к Google, вот что я получил за "правильный путь", вылавливать любое исключение, которое Net:: HTTP может бросить на вас:

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 ниль и т.д.). Конечно, все это будет намного проще, если возможно ошибки имели общего предка.

Проблемы, которые я видел при работе с Net:: HTTP, заставили меня интересно, не стоит ли писать новую клиентскую библиотеку HTTP. Тот, который легче было издеваться над тестами, и не имел всех этих уродливые маленькие грани.

То, что я делал и видел большинство людей, - это отойти от Net:: HTTP и перейти на сторонние HTTP-библиотеки, такие как:

httparty и faraday p >

Ответ 2

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

Как указано Ответ Майка Льюиса, Сообщение блога Tammer Saleh предлагает спасти из-за больших исключений, но это еще недостаток. Есть некоторые исключения, из которых он не спасает, например Errno::EHOSTUNREACH, Errno::ECONNREFUSED, и возможно некоторые исключения socket.

Итак, как я узнал в трансляции старого потока ruby-dev, лучшим решением является спасение от StandardError, к сожалению:

begin
  response = Net::HTTP.get_response(uri)
rescue StandardError
  false
end

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

Ответ 3

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

Ответ 4

Другим подходом является объединение всех этих исключений в константу, а затем повторное использование этой константы, например:

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

Он намного удобнее и чище.

Однако слово предупреждения. Я скопировал список возможных исключений из вышеупомянутого блога Tammer Saleh, и я знаю, что его список неполный. Например, Net::HTTP.get(URI("wow")) вызывает Errno::ECONNREFUSED, который не указан. Кроме того, я не удивлюсь, если список должен быть изменен для разных версий Ruby.

По этой причине я рекомендую придерживаться rescue StandardError в большинстве случаев. Чтобы избежать слишком много ловушек, перемещайтесь как можно дальше за пределы блока start-rescue-end, желательно оставить только вызов одного из методов Net::HTTP.