2011-03-20 37 views
35

Cách tốt nhất để giải cứu ngoại lệ từ Net :: HTTP là gì?Cách tốt nhất để xử lý ngoại lệ từ Net :: HTTP là gì?

Trường hợp ngoại lệ được ném được mô tả trong số socket.c của Ruby, như Errno::ETIMEDOUT, Errno::ECONNRESETErrno::ECONNREFUSED. Các lớp cơ sở cho tất cả trong số này là SystemCallError, nhưng nó cảm thấy lạ để viết mã như sau vì SystemCallError dường như quá xa so với thực hiện một cuộc gọi HTTP:

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

là nó chỉ cho tôi? Có cách nào tốt hơn để xử lý việc này ngoài việc sửa chữa Net::HTTP để xử lý các trường hợp ngoại lệ Errno có khả năng sẽ bật lên và đóng gói chúng trong một phụ huynh HttpRequestException?

+2

Cảm ơn mọi người! Tôi đã kết thúc đóng gói các câu trả lời dưới dạng một Gem Ruby mà tôi có thể sử dụng trong tương lai để đối phó với tình huống này: net_http_exception_fix [https://github.com/edward/net_http_exception_fix] –

+1

Liên kết chính xác: https://github.com/edward/net_http_exception_fix (bình luận của Edward trích thêm một "]" vào URL). – myhd

+1

Tôi đã viết một thư viện khác giải quyết cùng một vấn đề theo một cách khác: http://github.com/barsoom/net_http_timeout_errors –

Trả lời

34

Tôi đồng ý rằng đó là một nỗi đau tuyệt đối để xử lý tất cả các ngoại lệ tiềm ẩn. Hãy xem this để xem ví dụ:

Làm việc với Net::HTTP có thể gây đau. Nó có khoảng 40 cách khác nhau để thực hiện bất kỳ tác vụ nào và khoảng 50 ngoại lệ mà nó có thể ném.

Chỉ cần cho tình yêu của google, đây là những gì tôi đã có cho "đúng cách" bắt bất kỳ ngoại lệ mà Net :: HTTP có thể ném vào bạn:

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 

Tại sao không chỉ rescue Exception => e? Đó là một thói quen xấu để xâm nhập, như nó ẩn bất kỳ vấn đề nào trong mã thực tế của bạn (như SyntaxErrors, whiny nils, v.v ...). Tất nhiên, điều này sẽ dễ dàng hơn nhiều nếu các lỗi có thể có một tổ tiên chung.

Các vấn đề tôi gặp phải khi xử lý Net :: HTTP đã làm cho tôi tự hỏi liệu sẽ không đáng để viết một thư viện máy khách HTTP mới. Một cách dễ dàng hơn để thử nghiệm trong các thử nghiệm và không có tất cả các khía cạnh nhỏ xíu này .

Những gì tôi đã làm, và thấy hầu hết mọi người làm, là di chuyển ra khỏi Net :: HTTP và di chuyển đến 3 thư viện của bên HTTP như:

httpartyfaraday

+4

Hoặc [Open-URI] của riêng Ruby (http://rubydoc.info/stdlib/open-uri/1.9.2/frames) hoặc [HTTPClient] (http://rubydoc.info/gems/httpclient/2.1.6.1/frames) hoặc [Typhoeus] (https://github.com/dbalatero/typhoeus). Open-URI là một giao diện đơn giản hơn nhiều cho các tác vụ nhanh. HTTPClient và Typhoeus là sức mạnh công nghiệp, xử lý luồng và tất cả các loại nâng hạng nặng khác. –

+0

'HTTPClient' rất nóng! Tôi nghĩ tôi sẽ sử dụng nó trong tương lai. Cảm ơn bạn đã tham khảo. –

+0

Google-fu của bạn vượt trội và tôi rất vui khi được tham gia vào công việc của Tammer. Đó chỉ là những gì tôi đang tìm kiếm. –

3

trực giác của bạn trên điều này là đúng, đối với giải pháp mạnh mẽ nhất, tôi có thể giải cứu từng cá nhân (hoặc theo nhóm nhỏ) và thực hiện hành động thích hợp, như thử lại kết nối, hoặc từ bỏ yêu cầu tất cả cùng nhau. Tôi muốn tránh sử dụng một cấp cứu rất cao/chung chung vì nó có thể bắt ngoại lệ mà tôi không chuẩn bị cho hoặc không mong đợi.

+1

Ok, tuyệt - vui khi biết tôi không phải là người duy nhất :) Tôi đã đóng gói lời khuyên của bạn + @MikeLewis thành một viên ngọc gọi là net_http_exception_fix –

16

Tôi gặp vấn đề tương tự, và sau rất nhiều nghiên cứu, tôi nhận ra cách tốt nhất để xử lý tất cả ngoại lệ Net :: Phương pháp HTTP sẽ ném là để giải cứu khỏi StandardError.

Được chỉ định bởi Mike Lewis's answer, Tammer Saleh blog post đề xuất cứu từ nhiều ngoại lệ, nhưng đó vẫn là lỗi. Có một số ngoại lệ mà anh ta không giải cứu từ, như Errno::EHOSTUNREACH, Errno::ECONNREFUSED và có thể một số ngoại lệ socket.

Vì vậy, khi tôi phát hiện ra trong tenderlove's translation of an old ruby-dev thread, giải pháp tốt nhất được giải cứu từ StandardError, không may:

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

Đó là khủng khiếp, nhưng nếu bạn muốn hệ thống của bạn không phá vỡ vì những trường hợp ngoại lệ khác, sử dụng cách tiếp cận này.

0

cách tiếp cận khác là tổng hợp tất cả những trường hợp ngoại lệ trong một hằng số, và sau đó tái sử dụng này không đổi, ví dụ .:

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 

Nó là xa duy trì và sạch hơn.

Tuy nhiên, cảnh báo. Tôi đã sao chép danh sách ngoại lệ có thể có từ bài đăng trên blog của Tammer Saleh nói trên và tôi biết rằng danh sách của anh ấy chưa đầy đủ. Ví dụ: Net::HTTP.get(URI("wow")) tăng số Errno::ECONNREFUSED không được liệt kê. Ngoài ra, tôi sẽ không ngạc nhiên nếu danh sách nên được sửa đổi cho các phiên bản Ruby khác nhau.

Vì lý do này, tôi khuyên bạn nên gắn bó với rescue StandardError trong hầu hết các trường hợp. Để tránh bị bắt quá nhiều, di chuyển càng nhiều càng tốt bên ngoài khối bắt đầu-cứu-end, tốt nhất là chỉ để lại một cuộc gọi đến một trong các phương pháp Net::HTTP.

Các vấn đề liên quan