zoukankan      html  css  js  c++  java
  • 使用Apache HttpClient 4.x进行异常重试

    在进行http请求时,难免会遇到请求失败的情况,失败后需要重新请求,尝试再次获取数据。

    Apache的HttpClient提供了异常重试机制,在该机制中,我们可以很灵活的定义在哪些异常情况下进行重试。

    重试前提

    被请求的方法必须是幂等的:就是多次请求服务端结果应该是准确且一致的。 

    适合的方法:比如根据ID,修改人员姓名,无论请求多次结果都是一样,这就是幂等。 
    不适合的方法:比如减少账号50元,多次请求将多次扣减。

    实现方式

    想要实现异常重试,需要实现它提供的一个接口  HttpRequestRetryHandler ,并实现 retryRequest 方法。然后set到HttpClient中。该httpClient就具备了重试机制。
     
    HttpClient自身提供了 StandardHttpRequestRetryHandler 和 DefaultHttpRequestRetryHandler 两个实现类。 DefaultHttpRequestRetryHandler 继承自 DefaultHttpRequestRetryHandler , StandardHttpRequestRetryHandler 默认几个方法为幂等,如PUT、GET、HEAD等除POST外的方法,如果自定义可以参考它的实现方式。
     
    代码如下:
      1 import java.io.IOException;
      2 import java.io.InterruptedIOException;
      3 import java.net.ConnectException;
      4 import java.net.UnknownHostException;
      5 
      6 import javax.net.ssl.SSLException;
      7 
      8 import org.apache.commons.lang3.ObjectUtils;
      9 import org.apache.commons.lang3.StringUtils;
     10 import org.apache.http.Consts;
     11 import org.apache.http.HttpEntityEnclosingRequest;
     12 import org.apache.http.HttpRequest;
     13 import org.apache.http.HttpStatus;
     14 import org.apache.http.ParseException;
     15 import org.apache.http.client.HttpRequestRetryHandler;
     16 import org.apache.http.client.config.RequestConfig;
     17 import org.apache.http.client.methods.CloseableHttpResponse;
     18 import org.apache.http.client.methods.HttpPost;
     19 import org.apache.http.client.protocol.HttpClientContext;
     20 import org.apache.http.entity.ContentType;
     21 import org.apache.http.entity.StringEntity;
     22 import org.apache.http.impl.client.CloseableHttpClient;
     23 import org.apache.http.impl.client.HttpClients;
     24 import org.apache.http.protocol.HttpContext;
     25 import org.apache.http.util.EntityUtils;
     26 
     27 /**
     28  * @author 29  *
     30  * @date 2017年5月18日 上午9:17:30
     31  *
     32  * @Description
     33  */
     34 public class HttpPostUtils {
     35     /**
     36      * 
     37      * @param uri
     38      *            the request address
     39      * @param json
     40      *            the request data that must be a JSON string
     41      * @param retryCount
     42      *            the number of times this method has been unsuccessfully
     43      *            executed
     44      * @param connectTimeout
     45      *            the timeout in milliseconds until a connection is established
     46      * @param connectionRequestTimeout
     47      *            the timeout in milliseconds used when requesting a connection
     48      *            from the connection manager
     49      * @param socketTimeout
     50      *            the socket timeout in milliseconds, which is the timeout for
     51      *            waiting for data or, put differently, a maximum period
     52      *            inactivity between two consecutive data packets
     53      * @return null when method parameter is null, "", " "
     54      * @throws IOException
     55      *             if HTTP connection can not opened or closed successfully
     56      * @throws ParseException
     57      *             if response data can not be parsed successfully
     58      */
     59     public String retryPostJson(String uri, String json, int retryCount, int connectTimeout,
     60             int connectionRequestTimeout, int socketTimeout) throws IOException, ParseException {
     61         if (StringUtils.isAnyBlank(uri, json)) {
     62             return null;
     63         }
     64 
     65         HttpRequestRetryHandler httpRequestRetryHandler = new HttpRequestRetryHandler() {
     66 
     67             @Override
     68             public boolean retryRequest(IOException exception, int executionCount, HttpContext context) {
     69                 if (executionCount > retryCount) {
     70                     // Do not retry if over max retry count
     71                     return false;
     72                 }
     73                 if (exception instanceof InterruptedIOException) {
     74                     // An input or output transfer has been terminated
     75                     return false;
     76                 }
     77                 if (exception instanceof UnknownHostException) {
     78                     // Unknown host 修改代码让不识别主机时重试,实际业务当不识别的时候不应该重试,再次为了演示重试过程,执行会显示retryCount次下面的输出
     79                     System.out.println("不识别主机重试"); return true;
     80                 }
     81                 if (exception instanceof ConnectException) {
     82                     // Connection refused
     83                     return false;
     84                 }
     85                 if (exception instanceof SSLException) {
     86                     // SSL handshake exception
     87                     return false;
     88                 }
     89                 HttpClientContext clientContext = HttpClientContext.adapt(context);
     90                 HttpRequest request = clientContext.getRequest();
     91                 boolean idempotent = !(request instanceof HttpEntityEnclosingRequest);
     92                 if (idempotent) {
     93                     // Retry if the request is considered idempotent
     94                     return true;
     95                 }
     96                 return false;
     97             }
     98         };
     99 
    100         CloseableHttpClient client = HttpClients.custom().setRetryHandler(httpRequestRetryHandler).build();
    101         HttpPost post = new HttpPost(uri);
    102         // Create request data
    103         StringEntity entity = new StringEntity(json, ContentType.APPLICATION_JSON);
    104         // Set request body
    105         post.setEntity(entity);
    106 
    107         RequestConfig config = RequestConfig.custom().setConnectTimeout(connectTimeout)
    108                 .setConnectionRequestTimeout(connectionRequestTimeout).setSocketTimeout(socketTimeout).build();
    109         post.setConfig(config);
    110         // Response content
    111         String responseContent = null;
    112         CloseableHttpResponse response = null;
    113         try {
    114             response = client.execute(post, HttpClientContext.create());
    115             if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
    116                 responseContent = EntityUtils.toString(response.getEntity(), Consts.UTF_8.name());
    117             }
    118         } finally {
    119             if (ObjectUtils.anyNotNull(response)) {
    120                 response.close();
    121             }
    122             if (ObjectUtils.anyNotNull(client)) {
    123                 client.close();
    124             }
    125         }
    126         return responseContent;
    127     }

    在实现的 retryRequest 方法中,遇到不识别主机异常,返回 true ,请求将重试。最多重试请求retryCount次。

  • 相关阅读:
    祝各位博友新年快乐,全家幸福,大展宏图,财源滚滚!
    Android中级第五讲GPRS定位的实现
    Android高级开发第二讲Android中API翻译之Activity
    Android 图标、音频、颜色RGB工具集
    Android初级开发第八讲之startActivityForResult方法讲解
    Android高级开发第三讲应用程序基础
    Android高级开发第四讲API之Service
    Android高级开发第五讲API之Content Providers
    物联网操作系统是否需要基于Java和虚拟机进行构筑
    Android高级开发第四讲API之Intents and Intent Filters
  • 原文地址:https://www.cnblogs.com/warehouse/p/6879292.html
Copyright © 2011-2022 走看看