2012-05-11 31 views
51

Tôi có một webservice chấp nhận phương thức POST với XML. Nó làm việc tốt sau đó tại một số dịp ngẫu nhiên, nó không giao tiếp với máy chủ ném IOException với thông báo The target server failed to respond. Các cuộc gọi tiếp theo hoạt động tốt.Lỗi tạm thời Apache HttpClient: NoHttpResponseException

Nó xảy ra chủ yếu, khi tôi thực hiện một số cuộc gọi và sau đó để ứng dụng của tôi nhàn rỗi trong khoảng 10-15 phút. cuộc gọi đầu tiên mà tôi thực hiện sau đó sẽ trả về lỗi này.

tôi đã cố gắng vài điều ...

tôi thiết lập xử lý retry như

HttpRequestRetryHandler retryHandler = new HttpRequestRetryHandler() { 

      public boolean retryRequest(IOException e, int retryCount, HttpContext httpCtx) { 
       if (retryCount >= 3){ 
        Logger.warn(CALLER, "Maximum tries reached, exception would be thrown to outer block"); 
        return false; 
       } 
       if (e instanceof org.apache.http.NoHttpResponseException){ 
        Logger.warn(CALLER, "No response from server on "+retryCount+" call"); 
        return true; 
       } 
       return false; 
      } 
     }; 

     httpPost.getParams().setParameter(HttpMethodParams.RETRY_HANDLER, retryHandler); 

nhưng retey này không bao giờ được gọi tới. (vâng tôi đang sử dụng đúng mệnh đề instanceof). Trong khi gỡ lỗi lớp này không bao giờ được gọi.

Tôi thậm chí đã thử thiết lập HttpProtocolParams.setUseExpectContinue(httpClient.getParams(), false); nhưng không sử dụng. Ai đó có thể gợi ý tôi có thể làm gì bây giờ?

QUAN TRỌNG Bên cạnh việc tìm hiểu lý do tại sao tôi nhận ngoại lệ, một trong những mối quan tâm quan trọng tôi có là tại sao người thử lại không hoạt động ở đây?

+0

Tôi không nghĩ rằng đó là một cái gì đó với mã khách hàng. Có thể máy chủ đích quá bận rộn trong việc xử lý phản hồi không? – kosa

+0

Tôi đã cố gắng để đánh bom máy chủ đích nhưng nó hoạt động tốt. Tôi thậm chí đã cố gắng thực hiện các bước tương tự để tái sản xuất lỗi bằng cách sử dụng fiddler, nhưng không may mắn! –

+0

Loại máy chủ web nào đang chạy dịch vụ và trong thời gian chờ 10-15 phút là dịch vụ nhận các yêu cầu khác hoặc dịch vụ không hoạt động? – Shawn

Trả lời

79

Các kết nối liên tục có khả năng nhất được giữ bởi trình quản lý kết nối trở nên cũ. Đó là, máy chủ mục tiêu tắt kết nối vào cuối của nó mà không HttpClient có thể phản ứng với sự kiện đó, trong khi kết nối đang được nhàn rỗi, do đó kết xuất một nửa đóng hoặc 'cũ'. Thông thường đây không phải là một vấn đề. HttpClient sử dụng một số kỹ thuật để xác minh tính hợp lệ của kết nối khi thuê từ hồ bơi. Ngay cả khi kiểm tra kết nối cũ bị tắt và kết nối cũ được sử dụng để truyền tải thông báo yêu cầu, việc thực hiện yêu cầu thường không thành công trong thao tác ghi với SocketException và được tự động thử lại. Tuy nhiên trong một số trường hợp, thao tác ghi có thể chấm dứt mà không có ngoại lệ và hoạt động đọc tiếp theo trả về -1 (cuối luồng). Trong trường hợp này HttpClient không có lựa chọn nào khác ngoài việc giả sử yêu cầu đã thành công nhưng máy chủ không phản hồi nhiều khả năng do lỗi không mong muốn ở phía máy chủ.

Cách đơn giản nhất để khắc phục tình huống là loại bỏ các kết nối đã hết hạn và kết nối đã không hoạt động lâu hơn, ví dụ, 1 phút từ hồ bơi sau một khoảng thời gian không hoạt động. Để biết chi tiết, vui lòng xem this section of the HttpClient tutorial.

+0

Tôi đang sử dụng HTTTPClient 4.5.1, ở đây có hai máy chủ thử lại liên tục không thành công nhưng lần thứ ba thành công, vậy tại sao nó không kết nối trong lần thử đầu tiên ngay cả khi tôi giữ thời gian 1 phút như được đo. –

+0

@oleg, sự khác nhau giữa các kết nối nhàn rỗi và hết hạn là gì? – Ales

+1

Một số kết nối có thể có thời gian hết hạn mà chúng được coi là không còn hiệu lực/có thể sử dụng lại được nữa. Các kết nối nhàn rỗi hoàn toàn hợp lệ và có thể sử dụng lại được nhưng không được sử dụng trong giây lát. – oleg

10

Câu trả lời được chấp nhận là đúng nhưng thiếu giải pháp. Để tránh lỗi này, bạn có thể thêm setHttpRequestRetryHandler (hoặc setRetryHandler cho các thành phần apache 4.4) cho ứng dụng khách HTTP của bạn như trong this answer.

+1

Cho rằng câu hỏi ban đầu chỉ định một POST, là một xử lý thử lại đúng cách tiếp cận ở đây? –

0

HttpClient 4.4 bị lỗi trong khu vực này liên quan đến việc xác thực các kết nối cũ có thể có trước khi trở về người yêu cầu. Nó không xác thực xem kết nối có cũ hay không và sau đó kết quả là ngay lập tức NoHttpResponseException.

Sự cố này đã được giải quyết trong HttpClient 4.4.1. Xem this JIRArelease notes

+0

Tôi đang sử dụng phiên bản 4.5.3 nhưng vẫn nhận được ** NoHttpResponseException **. Trong trường hợp của tôi, tôi nhận được ngoại lệ này trong mọi yêu cầu liên tục thứ 4 hoặc thứ 5 không phải trong yêu cầu thứ nhất. Bất kỳ ý tưởng những gì có thể là lý do trong trường hợp của tôi? –

1

Ngày nay, hầu hết các kết nối HTTP là considered persistent unless declared otherwise. Tuy nhiên, để tiết kiệm tài nguyên máy chủ, kết nối hiếm khi được mở vĩnh viễn, thời gian chờ kết nối mặc định cho nhiều máy chủ khá ngắn, ví dụ 5 giây đối với Apache httpd 2.2 trở lên.

Lỗi org.apache.http.NoHttpResponseException có nhiều khả năng nhất từ ​​một kết nối liên tục đã bị máy chủ đóng.

Có thể đặt thời gian tối đa để giữ các kết nối không sử dụng được mở trong nhóm ứng dụng khách Apache Http, tính bằng mili giây.

Với mùa xuân Boot, một cách để đạt được điều này:

public class RestTemplateCustomizers { 
    static public class MaxConnectionTimeCustomizer implements RestTemplateCustomizer { 

     @Override 
     public void customize(RestTemplate restTemplate) { 
      HttpClient httpClient = HttpClientBuilder 
       .create() 
       .setConnectionTimeToLive(1000, TimeUnit.MILLISECONDS) 
       .build(); 

      restTemplate.setRequestFactory(
       new HttpComponentsClientHttpRequestFactory(httpClient)); 
     } 
    } 
} 

// In your service that uses a RestTemplate 
public MyRestService(RestTemplateBuilder builder) { 
    restTemplate = builder 
     .customizers(new RestTemplateCustomizers.MaxConnectionTimeCustomizer()) 
     .build(); 
} 
+0

Trong trường hợp của tôi, tôi nhận được ngoại lệ này trong mọi yêu cầu liên tục thứ 4 hoặc thứ 5 không phải trong yêu cầu thứ nhất. Bất kỳ ý tưởng những gì có thể là lý do trong trường hợp của tôi? –

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