Каков наилучший способ обработки исключений из 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
?
Ответы
Ответ 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
.