使用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  *
 29  * @date 2017年5月18日 上午9:17:30
 30  *
 31  * @Description
 32  */
 33 public class HttpPostUtils {
 34     /**
 35      * 
 36      * @param uri
 37      *            the request address
 38      * @param json
 39      *            the request data that must be a JSON string
 40      * @param retryCount
 41      *            the number of times this method has been unsuccessfully
 42      *            executed
 43      * @param connectTimeout
 44      *            the timeout in milliseconds until a connection is established
 45      * @param connectionRequestTimeout
 46      *            the timeout in milliseconds used when requesting a connection
 47      *            from the connection manager
 48      * @param socketTimeout
 49      *            the socket timeout in milliseconds, which is the timeout for
 50      *            waiting for data or, put differently, a maximum period
 51      *            inactivity between two consecutive data packets
 52      * @return null when method parameter is null, "", " "
 53      * @throws IOException
 54      *             if HTTP connection can not opened or closed successfully
 55      * @throws ParseException
 56      *             if response data can not be parsed successfully
 57      */
 58     public String retryPostJson(String uri, String json, int retryCount, int connectTimeout,
 59             int connectionRequestTimeout, int socketTimeout) throws IOException, ParseException {
 60         if (StringUtils.isAnyBlank(uri, json)) {
 61             return null;
 62         }
 63 
 64         HttpRequestRetryHandler httpRequestRetryHandler = new HttpRequestRetryHandler() {
 65 
 66             @Override
 67             public boolean retryRequest(IOException exception, int executionCount, HttpContext context) {
 68                 if (executionCount > retryCount) {
 69                     // Do not retry if over max retry count
 70                     return false;
 71                 }
 72                 if (exception instanceof InterruptedIOException) {
 73                     // An input or output transfer has been terminated
 74                     return false;
 75                 }
 76                 if (exception instanceof UnknownHostException) {
 77                     // Unknown host 修改代码让不识别主机时重试,实际业务当不识别的时候不应该重试,再次为了演示重试过程,执行会显示retryCount次下面的输出
 78                     System.out.println("不识别主机重试"); return true;
 79                 }
 80                 if (exception instanceof ConnectException) {
 81                     // Connection refused
 82                     return false;
 83                 }
 84                 if (exception instanceof SSLException) {
 85                     // SSL handshake exception
 86                     return false;
 87                 }
 88                 HttpClientContext clientContext = HttpClientContext.adapt(context);
 89                 HttpRequest request = clientContext.getRequest();
 90                 boolean idempotent = !(request instanceof HttpEntityEnclosingRequest);
 91                 if (idempotent) {
 92                     // Retry if the request is considered idempotent
 93                     return true;
 94                 }
 95                 return false;
 96             }
 97         };
 98 
 99         CloseableHttpClient client = HttpClients.custom().setRetryHandler(httpRequestRetryHandler).build();
100         HttpPost post = new HttpPost(uri);
101         // Create request data
102         StringEntity entity = new StringEntity(json, ContentType.APPLICATION_JSON);
103         // Set request body
104         post.setEntity(entity);
105 
106         RequestConfig config = RequestConfig.custom().setConnectTimeout(connectTimeout)
107                 .setConnectionRequestTimeout(connectionRequestTimeout).setSocketTimeout(socketTimeout).build();
108         post.setConfig(config);
109         // Response content
110         String responseContent = null;
111         CloseableHttpResponse response = null;
112         try {
113             response = client.execute(post, HttpClientContext.create());
114             if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
115                 responseContent = EntityUtils.toString(response.getEntity(), Consts.UTF_8.name());
116             }
117         } finally {
118             if (ObjectUtils.anyNotNull(response)) {
119                 response.close();
120             }
121             if (ObjectUtils.anyNotNull(client)) {
122                 client.close();
123             }
124         }
125         return responseContent;
126     }

 

转载自:http://www.cnblogs.com/wuxiaofeng/p/6879292.html,感谢分享。

posted @ 2017-06-20 20:35  Hugh.Hades  阅读(1757)  评论(0编辑  收藏  举报