2011-03-20 8 views
35

¿Cuál es la mejor forma de rescatar excepciones de Net :: HTTP?¿Cuál es la mejor forma de manejar excepciones de Net :: HTTP?

Las excepciones lanzadas se describen en Ruby's socket.c, como Errno::ETIMEDOUT, Errno::ECONNRESET y Errno::ECONNREFUSED. La clase base para todos estos es SystemCallError, pero se siente raro escribir código como el siguiente, porque SystemCallError parece tan lejos de hacer una llamada HTTP:

begin 
    response = Net::HTTP.get_response(uri) 
    response.code == "200" 
rescue SystemCallError 
    false 
end 

¿Soy yo? ¿Hay una mejor manera de manejar esto más allá de la fijación de Net::HTTP para manejar las excepciones Errno que probablemente aparecerían y las encapsularían en un padre HttpRequestException?

+2

¡Gracias a todos! Terminé empaquetando las respuestas en forma de Ruby Gem que puedo usar en el futuro para manejar esta situación: net_http_exception_fix [https://github.com/edward/net_http_exception_fix] –

+1

Enlace correcto: https://github.com/edward/net_http_exception_fix (el comentario de Edward sorbe un "]" extra en la URL). – myhd

+1

He escrito otra biblioteca que resuelve el mismo problema de otra manera: http://github.com/barsoom/net_http_timeout_errors –

Respuesta

34

Estoy de acuerdo que es un dolor absoluta para manejar todas las posibles excepciones. Mire this para ver un ejemplo:

Trabajar con Net::HTTP puede ser una molestia. Tiene alrededor de 40 maneras diferentes para hacer cualquier tarea, y alrededor de 50 excepciones que puede lanzar.

Sólo por el amor de Google, esto es lo que tengo para el "camino correcto" de la captura de cualquier excepción que Net :: HTTP puede tirar de ti:

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 

¿Por qué no rescue Exception => e? Es un mal hábito entrar, ya que oculta cualquier problema en el código real (como SyntaxErrors, whiny nils, etc.). Por supuesto, todo esto sería mucho más fácil si los posibles errores tuvieran un antecesor común.

Los problemas que he estado viendo al tratar con Net :: HTTP me han hecho que se pregunte si no valdría la pena escribir una nueva biblioteca de cliente HTTP. Uno que era más fácil de burlarse en las pruebas, y no tenía todas estas facetas feas .

Lo que he hecho, y he visto la mayoría de la gente, es alejarse de Net :: HTTP y mover a las bibliotecas 3 ª Parte HTTP como:

httparty y faraday

+4

O el propio [Uri-abierto] de Ruby (http://rubydoc.info/stdlib/open-uri/1.9.2/frames) o [HTTPClient] (http://rubydoc.info/gems/httpclient/2.1.6.1/frames) o [Typhoeus] (https://github.com/dbalatero/typhoeus). Open-URI es una interfaz mucho más simple para tareas rápidas. HTTPClient y Typhoeus son resistencia industrial, manejo de roscado y todo tipo de otros trabajos pesados. –

+0

'HTTPClient' está caliente! Creo que terminaré usando eso en el futuro. Gracias por la referencia. –

+0

Su Google-fu es superior y estoy feliz de haber aterrizado en el trabajo de Tammer. Eso es justo lo que estaba buscando. –

3

Su intuición esto es correcto, para la solución más robusta, probablemente rescataría a cada uno individualmente (o en pequeños grupos) y tomaré las medidas adecuadas, como intentar la conexión nuevamente o abandonar la solicitud todos juntos. Me gusta evitar el uso de un rescate genérico de alto nivel porque podría detectar excepciones para las que no estoy preparado o que no esperaba.

+1

Ok, genial - me alegra saber que no soy el único :) Terminé empaquetando tu consejo + @MikeLewis en una gema llamada net_http_exception_fix –

16

Experimenté el mismo problema, y ​​después de mucha investigación, me di cuenta de que la mejor manera de manejar todas las excepciones que los métodos de HTTP arrojarían es rescatar de StandardError.

Según lo apuntado por Mike Lewis's answer, Tammer Saleh blog post propone rescatar de muchas excepciones, pero todavía es un defecto. Hay algunas excepciones de las que no rescata, como Errno::EHOSTUNREACH, Errno::ECONNREFUSED, y posibles excepciones de socket.

Así, como descubrí en tenderlove's translation of an old ruby-dev thread, la mejor solución es el rescate de StandardError, por desgracia:

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

Es horrible, pero si usted quiere que su sistema no se rompe a causa de estas otras excepciones, el uso Este enfoque.

0

Otro método consiste en agregar todas estas excepciones en una constante, y luego volver a utilizar esta constante, por ejemplo .:

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 

Es mucho más fácil de mantener y más limpio.

Sin embargo, una palabra de advertencia. Copié la posible lista de excepciones de la publicación de blog de Tammer Saleh, y sé que su lista está incompleta. Por ejemplo, Net::HTTP.get(URI("wow")) aumenta Errno::ECONNREFUSED que no aparece en la lista. Además, no me sorprendería si la lista se modificara para las diferentes versiones de Ruby.

Por esta razón, le recomiendo que se adhiera a rescue StandardError en la mayoría de los casos. Para evitar atrapar demasiado, mueva tanto como sea posible fuera del bloque de inicio y final de rescate; preferiblemente, solo deje una llamada a uno de los métodos Net::HTTP.

Cuestiones relacionadas