HttpClient retry mechanism parse the source code (httpclient retry timeout does not resolve the problem)

 

Tips: Timeout retry solution at the bottom, you can directly view


First of all introduce my version is httpclient 4.3.4, is used in a manner PoolingHttpClientConnectionManager connection pool construction CloseableHttpClient, code is as follows:

Next, get requests execution as shown below:

See execute method, shown below until the

 

doExecute 方法,可以看到多种实现方式,查看构造httpclient的build 构造方法到最后一行 发现 new InternalHttpClient ,然后进入其 doExecute 方法 ,直到下图的这一行

Will be found in a chain ClientExecChain execChain executed in the execution, the method continues to build httpclient of view, we can see the following section of code 3

   

There are multiple execution chain making the call, here is a chain of responsibility pattern design, each execChain chain will call on one

execute 方法,所以会依次进入 MainClientExec 、ProtocolExec 、RetryExec的 execute方法,首先查看MainClientExec 的execute方法 查看到下面这行代码

Holds a requestExecutor will perform, and then executes HttpRequestExecutor execute method 

This code execution http request a response. Now we assume that the request timeout, throws IOException to execute the method ProtocolExec in the following chart:

So the exception thrown execute the method continues in RetryExec, as shown below:

 

After there will be a cycle, Caught IOException due execAware.isAborted () by default returns false, will enter into retryHandler.retryRequest this method. The method then continue to build the image above to view httpclient will find if retry class is empty, The default configuration will DefaultHttpRequestRetryHandler, view their construction method, as shown below:

The default is 3 retries, the retry has not sent a request. Check its retry request method 

Can be seen only when the request is idempotent request is not complete and will retry sending, if thrown InterruptedIOException, UnknownHostException, ConnectException, SSLException four abnormal, http request will not be retried.

The figure we found a timeout exception are inherited from InterruptedIOException, so it is a connection timeout or read timeout will not trigger the retry mechanism.

Timeout retry httpClient solutions

My solution is to re-implement a retry class HttpRequestRetryHandler, code is as follows:

HttpRequestRetryHandler requestRetryHandler=new HttpRequestRetryHandler() {
   public boolean retryRequest(IOException exception, int executionCount, HttpContext context) {
      if (executionCount > 3) //超过重试次数,就放弃
         return false;
      if (exception instanceof NoHttpResponseException) {//没有响应,重试
         return true;
      }else if (exception instanceof ConnectTimeoutException) {//连接超时,重试
         return true;
      } else if (exception instanceof SocketTimeoutException) {//连接或读取超时,重试
         return true;
      }else if (exception instanceof SSLHandshakeException) {//本地证书异常
         return false;
      } else if (exception instanceof InterruptedIOException) {//被中断
         return false;
      } else if (exception instanceof UnknownHostException) {//找不到服务器
         return false;
      }  else if (exception instanceof SSLException) {//SSL异常
         return false;
      } else {
         LOGGER.error("未记录的请求异常:" + exception.getClass());
      }
      HttpClientContext clientContext = HttpClientContext.adapt(context);
      HttpRequest request = clientContext.getRequest();
      // 如果请求是幂等的,则重试
      if (!(request instanceof HttpEntityEnclosingRequest)) return true;
      return false;
   }
};
httpClient = HttpClients.custom().setConnectionManager(cm).setDefaultRequestConfig(requestConfig).setRetryHandler(requestRetryHandler).build();

The first executionCount is representative of the number of retries, and then return true representative of this exception will trigger retry

Published 25 original articles · won praise 51 · views 20000 +

Guess you like

Origin blog.csdn.net/Royal_lr/article/details/82148885