通过http做接口调用请求的时候,常常会因为网络抖动或者其他未知原因,造成接口在某个瞬间访问不了。此时需要增加重试机制。
HttpClient有重试机制,通过设置httpclient 的retryHandler来实现。
封装了一个HttpClientUtils的工具类中的获取线程池并设置retry机制的方法,代码如下:
package com.ly.storm.config;
import com.alibaba.fastjson.JSON;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Lists;
import org.apache.commons.httpclient.ConnectTimeoutException;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.http.HttpEntityEnclosingRequest;
import org.apache.http.HttpRequest;
import org.apache.http.NameValuePair;
import org.apache.http.NoHttpResponseException;
import org.apache.http.client.HttpRequestRetryHandler;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.protocol.HttpContext;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.annotation.PostConstruct;
import javax.net.ssl.SSLException;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.UnknownHostException;
import java.util.Enumeration;
import java.util.List;
import java.util.Map;
/**
* @Auther: fc.w
* @Date: 2018/12/12
*/
public class HttpClientUtils {
private static Logger logger = LoggerFactory.getLogger(HttpClientUtils.class);
private static final RequestConfig REQUEST_CONFIG_TIME_OUT = RequestConfig.custom()
.setSocketTimeout(20000)
.setConnectTimeout(50000)
.setConnectionRequestTimeout(50000)
.build();
private static PoolingHttpClientConnectionManager cm = null;
@PostConstruct
public void init() {
cm = new PoolingHttpClientConnectionManager();
cm.setMaxTotal(1000);
cm.setDefaultMaxPerRoute(1000);
}
/**
*
* @param isPooled 是否使用连接池
* @return
*/
public static CloseableHttpClient getClient(boolean isPooled) {
HttpRequestRetryHandler retryHandler = new HttpRequestRetryHandler() {
@Override
public boolean retryRequest(IOException e, int retryTimes, HttpContext httpContext) {
if (retryTimes > 2) {
return false;
}
if (e instanceof UnknownHostException || e instanceof ConnectTimeoutException
|| !(e instanceof SSLException) || e instanceof NoHttpResponseException) {
return true;
}
HttpClientContext clientContext = HttpClientContext.adapt(httpContext);
HttpRequest request = clientContext.getRequest();
boolean idempotent = !(request instanceof HttpEntityEnclosingRequest);
if (idempotent) {
// 如果请求被认为是幂等的,那么就重试。即重复执行不影响程序其他效果的
return true;
}
return false;
}
};
if (isPooled) {
return HttpClients.custom().setConnectionManager(cm).setRetryHandler(retryHandler).build();
}
return HttpClients.createDefault();
}
public static final String doPostWithRequest(String path, HttpServletRequest request) {
Enumeration params = request.getParameterNames();
List<NameValuePair> nameValuePairs = Lists.newArrayList();
while (params.hasMoreElements()) {
String paramName = (String) params.nextElement();
nameValuePairs.add(new BasicNameValuePair(paramName, request.getParameter(paramName)));
}
HttpPost httpPost = new HttpPost(path);
httpPost.setConfig(REQUEST_CONFIG_TIME_OUT);
try {
httpPost.setEntity(new UrlEncodedFormEntity(nameValuePairs));
return execReq(httpPost);
} catch (UnsupportedEncodingException e) {
logger.error("do post error: ", e);
}
return "";
}
public static final String doPost(String path, Map<String, Object> params) {
logger.debug("doPost from " + path, params);
HttpPost httpPost = new HttpPost(path);
httpPost.setConfig(REQUEST_CONFIG_TIME_OUT);
try {
httpPost.setEntity(new UrlEncodedFormEntity(createParams(params)));
String bodyAsString = execReq(httpPost);
if (bodyAsString != null) return bodyAsString;
} catch (UnsupportedEncodingException e) {
logger.error(e.getMessage(), e);
}
return errorResponse("-2", "unknown error");
}
private static List<NameValuePair> createParams(Map<String, Object> params) {
List<NameValuePair> nameValuePairs = Lists.newArrayList();
for (Map.Entry<String, Object> entry : params.entrySet()) {
nameValuePairs.add(new BasicNameValuePair(entry.getKey(), String.valueOf(entry.getValue())));
}
return nameValuePairs;
}
private static String execReq(HttpPost httpPost) {
try {
CloseableHttpResponse response = getClient(true).execute(httpPost);
if (response != null) {
try {
if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
return EntityUtils.toString(response.getEntity());
} else {
return errorResponse(String.valueOf(response.getStatusLine().getStatusCode()),
"http post request error: " + httpPost.getURI());
}
} finally {
EntityUtils.consume(response.getEntity());
}
} else {
return errorResponse("-1", "response is null");
}
} catch (IOException e) {
logger.error("doPost error: ", e);
}
return errorResponse("-3", "unknown error");
}
private static String errorResponse(String code, String msg) {
return JSON.toJSONString(ImmutableMap.of("code", code, "msg", msg));
}
}
网友评论