通过http做接口调用请求的时候,常常会因为网络抖动或者其他未知原因,造成接口在某个瞬间访问不了。此时需要增加重试机制。刚出来的时候掉接口需要三次重试,由于对httpclient不是很了解。只能在for循环里面对异常经常处理并重新调接口。后来做http服务端的时候,有次debug偶然发现客户端调一次请求,服务端会跳多次debug,后来查阅资料发现httpclient有重试机制。
今天做了个通天塔接口重试的需求,便想起来了httpclient的重试机制。
查了很久资料,也测试了很多次。后来终于成功了。是通过设置httpclient 的retryHandler来实现。
不多说废话,直接贴代码,如下:
/**
* @param isPooled 是否使用连接池
*/
public static CloseableHttpClient getClient(boolean isPooled) {
HttpRequestRetryHandler handler = new HttpRequestRetryHandler() {
@Override
public boolean retryRequest(IOException arg0, int retryTimes, HttpContext arg2) {
if (retryTimes > 2) {
return false;
}
if (arg0 instanceof UnknownHostException || arg0 instanceof ConnectTimeoutException
|| !(arg0 instanceof SSLException) || arg0 instanceof NoHttpResponseException) {
return true;
}
HttpClientContext clientContext = (arg2);
HttpRequest request = ();
boolean idempotent = !(request instanceof HttpEntityEnclosingRequest);
if (idempotent) {
// 如果请求被认为是幂等的,那么就重试。即重复执行不影响程序其他效果的
return true;
}
return false;
}
};
if (isPooled) {
return ().setConnectionManager(cm).setRetryHandler(handler).build();
}
return ();
}
上面的代码是封装了一个HttpClientUtil的工具类中的获取线程池并设置retry机制的方法。整个HttpClientUtil文件如下:
package ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import org.;
import org.;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
@Component
public class HttpClientUtil {
private static Logger logger = ();
private static final RequestConfig REQUEST_CONFIG_TIME_OUT = ()
.setSocketTimeout(5000)
.setConnectTimeout(5000)
.setConnectionRequestTimeout(5000)
.build();
private static PoolingHttpClientConnectionManager cm = null;
@PostConstruct
public void init() {
cm = new PoolingHttpClientConnectionManager();
(1000);
(1000);
}
/**
* @param isPooled 是否使用连接池
*/
public static CloseableHttpClient getClient(boolean isPooled) {
HttpRequestRetryHandler handler = new HttpRequestRetryHandler() {
@Override
public boolean retryRequest(IOException arg0, int retryTimes, HttpContext arg2) {
if (retryTimes > 2) {
return false;
}
if (arg0 instanceof UnknownHostException || arg0 instanceof ConnectTimeoutException
|| !(arg0 instanceof SSLException) || arg0 instanceof NoHttpResponseException) {
return true;
}
HttpClientContext clientContext = (arg2);
HttpRequest request = ();
boolean idempotent = !(request instanceof HttpEntityEnclosingRequest);
if (idempotent) {
// 如果请求被认为是幂等的,那么就重试。即重复执行不影响程序其他效果的
return true;
}
return false;
}
};
if (isPooled) {
return ().setConnectionManager(cm).setRetryHandler(handler).build();
}
return ();
}
public static final String doPostWithRequest(String path, HttpServletRequest request) {
Enumeration params = ();
List<NameValuePair> nameValuePairs = ();
while (()) {
String paramName = (String) ();
(new BasicNameValuePair(paramName, (paramName)));
}
HttpPost httpPost = new HttpPost(path);
(REQUEST_CONFIG_TIME_OUT);
try {
(new UrlEncodedFormEntity(nameValuePairs));
return execReq(httpPost);
} catch (UnsupportedEncodingException e) {
("do post error: ", e);
}
return "";
}
public static final String doPost(String path, Map<String, Object> params) {
("doPost from " + path, params);
HttpPost httpPost = new HttpPost(path);
(REQUEST_CONFIG_TIME_OUT);
try {
(new UrlEncodedFormEntity(createParams(params)));
String bodyAsString = execReq(httpPost);
if (bodyAsString != null) return bodyAsString;
} catch (UnsupportedEncodingException e) {
((), e);
}
return errorResponse("-2", "unknown error");
}
private static String execReq(HttpPost httpPost) {
try {
CloseableHttpResponse response = getClient(true).execute(httpPost);
if (response != null) {
try {
if (().getStatusCode() == HttpStatus.SC_OK) {
return (());
} else {
return errorResponse((().getStatusCode()),
"http post request error: " + ());
}
} finally {
(());
}
} else {
return errorResponse("-1", "response is null");
}
} catch (IOException e) {
("doPost error: ", e);
}
return errorResponse("-3", "unknown error");
}
private static String errorResponse(String code, String msg) {
return (("code", code, "msg", msg));
}
private static List<NameValuePair> createParams(Map<String, Object> params) {
List<NameValuePair> nameValuePairs = ();
for (<String, Object> entry : ()) {
(new BasicNameValuePair((), (())));
}
return nameValuePairs;
}
}
httpclient的调用如下:
String bingoPortalResStr = HttpClientUtil.doPostWithRequest(path, request);
参考:/p/481cbfcd3f13