使用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,感谢分享。