2012-05-11 132 views
51

私はXMLでPOSTメソッドを受け入れているwebserviceを持っています。それは正常にいくつかのランダムな機会にうまくいきます、それはメッセージとのIOExceptionをスローするサーバーとの通信に失敗しますThe target server failed to respond。その後の呼び出しは正常に動作します。Apache HttpClient暫定的なエラー:NoHttpResponseException

ほとんどの場合、私はいくつかの呼び出しを行い、10-15分のように私のアプリケーションをアイドル状態のままにしています。それ以降の最初の呼び出しでこのエラーが返されます。私は物事のカップルを試してみました

...

Iセットアップ

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); 

などの再試行ハンドラが、これreteyは決して呼ばないました。 (はい、私は正しいinstanceof句を使用しています)。このクラスをデバッグすることは決して呼び出されません。

私もHttpProtocolParams.setUseExpectContinue(httpClient.getParams(), false);を設定しようとしましたが、使用しませんでした。誰かが今何をすることができるかを提案することはできますか?

重要 retryhandlerがここで働いていない理由を私は例外を取得しています理由を考え出すのほかに、私が持っている重要な問題の一つはありますか?

+0

を私はそれがクライアントコードで何かあるとは思いません。宛先サーバーが応答を処理するには多忙であるかもしれませんか? – kosa

+0

宛先サーバーを攻撃するためにフィドラーを試しましたが、うまくいきました。私も、同じステップを実行して、フィドラーを使用してエラーを再現しようとしましたが、運はありません! –

+0

サービスを実行しているWebサーバの種類は何ですか?また、10〜15分待機中にサービスが他の要求を受信して​​いるか、サービスがアイドル状態になっていますか? – Shawn

答えて

79

接続マネージャによって保持されている可能性が最も高い永続的な接続は失効します。つまり、ターゲットサーバーは、接続がアイドル状態にある間にHttpClientがそのイベントに反応できるようにすることなく、接続の終了をシャットダウンし、接続が半分または '無効'になるようにします。通常これは問題ではありません。 HttpClientはプールからのリース時に接続の有効性を検証するためにいくつかの手法を採用しています。無効な接続チェックが無効で、古い接続がリクエストメッセージを送信するために使用されても、リクエスト実行は通常、SocketExceptionを使った書き込み操作で失敗し、自動的に再試行されます。しかし、状況によっては、書き込み操作は例外なく終了することができ、その後の読み取り操作は-1(ストリームの終わり)を返します。この場合、HttpClientには他の選択肢はありませんが、要求は成功したものと見なされますが、サーバー側で予期しないエラーが発生したためにサーバーが最も応答しなくなりました。

この状況を改善する最も簡単な方法は、期限切れの接続があった後に、接続から1分以上経過していない接続や接続を削除することです。詳細はthis section of the HttpClient tutorialを参照してください。

+0

私はHTTTPClient 4.5.1を使用しています。ここでは、2つの連続した再試行サーバーが応答に失敗しましたが、3回目は成功したので、最初の試行で接続しません。 –

+0

@oleg、アイドル接続と期限切れ接続の違いは何ですか? – Ales

+1

接続の中には有効期限/再使用可能ではないとみなされる有効期限があります。アイドル接続は完全に有効で再利用可能ですが、一時的に使用されません。 – oleg

10

解決済みですが解決策がありません。このエラーを回避するには、HTTPクライアントのsetHttpRequestRetryHandler(またはapacheコンポーネント4.4のsetRetryHandler)をthis answerのように追加します。

+1

オリジナルの質問でPOSTが指定されているとすれば、リトライハンドラは正しいアプローチですか? –

0

HttpClient 4.4は、リクエスタに返す前に失効している可能性のある接続の検証に関するこのバグの影響を受けました。 は、接続が古くなったかどうかを検証していないため、即時にNoHttpResponseExceptionが返されます。

この問題はHttpClient 4.4.1で解決されました。 this JIRArelease notes

+0

私は4.5.3バージョンを使用していますが、まだ** NoHttpResponseException **を取得しています。私の場合、1回目のリクエストではなく、4回目または5回目のリクエストごとにこの例外を取得しています。私の場合、どんな理由が考えられますか? –

1

今日、ほとんどのHTTP接続はconsidered persistent unless declared otherwiseです。ただし、サーバーのリソースを節約するために、接続は永久に開かれることはほとんどありません。多くのサーバーのデフォルトの接続タイムアウトはかなり短く、Apacheのhttpd 2.2以上では5秒です。

org.apache.http.NoHttpResponseExceptionエラーは、サーバーによって閉じられた1つの永続的な接続から発生している可能性が最も高いです。

未使用の接続をApache Httpクライアントプールで開いておく時間をミリ秒単位で設定できます。春ブーツ、これを達成するための一つの方法では

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

私の場合、1回目のリクエストではなく、4回目または5回目のリクエストごとにこのExceptionを取得しています。私の場合、どんな理由が考えられますか? –

関連する問題