Каков наилучший способ обработки исключений из Net :: HTTP? - PullRequest
44 голосов
/ 20 марта 2011

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

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

Ответы [ 4 ]

42 голосов
/ 20 марта 2011

Я согласен, что справляться со всеми потенциальными исключениями - абсолютная боль. Посмотрите на this , чтобы увидеть пример:

Работа с 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 и Фарадей

21 голосов
/ 04 августа 2012

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

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

Итак, как я обнаружил в переводе tenderlove старой ветки ruby-dev , лучшее решение - это спасение от StandardError, к сожалению:

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

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

3 голосов
/ 20 марта 2011

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

1 голос
/ 27 октября 2017

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

.
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

Гораздо проще в обслуживании и чистоте.

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

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

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