diff --git a/changelog.txt b/changelog.txt
index 37acc9d9..a8f2e573 100644
--- a/changelog.txt
+++ b/changelog.txt
@@ -2,6 +2,13 @@ WEIXIN-POPULAR CHANGELOG
===========================
https://github.com/liyiorg/weixin-popular
+Changes in version 2.6.3 (2016-03-25)
+-------------------------------------
+* weixin.popular.client.HttpClientFactory 修改
+* 增加请求超时设置,默认5秒。
+* 增加异常请求重试,默认失败重试2次。
+
+
Changes in version 2.6.2 (2016-03-10)
-------------------------------------
* weixin.popular.api.MediaAPI bug 修复
diff --git a/pom.xml b/pom.xml
index 3ad4b33d..1546a400 100644
--- a/pom.xml
+++ b/pom.xml
@@ -3,7 +3,7 @@
4.0.0
weixin
weixin-popular
- 2.6.2-RELEASE
+ 2.6.3-RELEASE
https://github.com/liyiorg/weixin-popular
diff --git a/src/main/java/weixin/popular/client/HttpClientFactory.java b/src/main/java/weixin/popular/client/HttpClientFactory.java
index 6b964924..f10ba24f 100644
--- a/src/main/java/weixin/popular/client/HttpClientFactory.java
+++ b/src/main/java/weixin/popular/client/HttpClientFactory.java
@@ -1,5 +1,8 @@
package weixin.popular.client;
+import java.io.IOException;
+import java.io.InterruptedIOException;
+import java.net.UnknownHostException;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
@@ -7,12 +10,21 @@
import java.security.UnrecoverableKeyException;
import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLException;
+import org.apache.http.HttpEntityEnclosingRequest;
+import org.apache.http.HttpRequest;
+import org.apache.http.client.HttpRequestRetryHandler;
+import org.apache.http.client.protocol.HttpClientContext;
+import org.apache.http.config.SocketConfig;
+import org.apache.http.conn.ConnectTimeoutException;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLContexts;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
+import org.apache.http.impl.conn.BasicHttpClientConnectionManager;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
+import org.apache.http.protocol.HttpContext;
/**
* httpclient 4.3.x
@@ -22,12 +34,24 @@
public class HttpClientFactory{
private static final String[] supportedProtocols = new String[]{"TLSv1"};
+
+ private static int timeout = 5000; //socket time out (default 5 s)
+
+ private static int retryExecutionCount = 2; //HttpClient retry execution count.
+
public static CloseableHttpClient createHttpClient() {
try {
SSLContext sslContext = SSLContexts.custom().useSSL().build();
+ BasicHttpClientConnectionManager connMrg = new BasicHttpClientConnectionManager();
+ SocketConfig socketConfig = SocketConfig.custom().setSoTimeout(timeout).build();
+ connMrg.setSocketConfig(socketConfig);
SSLConnectionSocketFactory sf = new SSLConnectionSocketFactory(sslContext,SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
- return HttpClientBuilder.create().setSSLSocketFactory(sf).build();
+ return HttpClientBuilder.create()
+ .setConnectionManager(connMrg)
+ .setSSLSocketFactory(sf)
+ .setRetryHandler(new HttpRequestRetryHandlerImpl())
+ .build();
} catch (KeyManagementException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
@@ -43,9 +67,12 @@ public static CloseableHttpClient createHttpClient(int maxTotal,int maxPerRoute)
PoolingHttpClientConnectionManager poolingHttpClientConnectionManager = new PoolingHttpClientConnectionManager();
poolingHttpClientConnectionManager.setMaxTotal(maxTotal);
poolingHttpClientConnectionManager.setDefaultMaxPerRoute(maxPerRoute);
+ SocketConfig socketConfig = SocketConfig.custom().setSoTimeout(timeout).build();
+ poolingHttpClientConnectionManager.setDefaultSocketConfig(socketConfig);
return HttpClientBuilder.create()
.setConnectionManager(poolingHttpClientConnectionManager)
.setSSLSocketFactory(sf)
+ .setRetryHandler(new HttpRequestRetryHandlerImpl())
.build();
} catch (KeyManagementException e) {
e.printStackTrace();
@@ -77,7 +104,12 @@ public static CloseableHttpClient createKeyMaterialHttpClient(KeyStore keystore,
SSLContext sslContext = SSLContexts.custom().useSSL().loadKeyMaterial(keystore, keyPassword.toCharArray()).build();
SSLConnectionSocketFactory sf = new SSLConnectionSocketFactory(sslContext,supportedProtocols,
null,SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
- return HttpClientBuilder.create().setSSLSocketFactory(sf).build();
+ SocketConfig socketConfig = SocketConfig.custom().setSoTimeout(timeout).build();
+ return HttpClientBuilder.create()
+ .setDefaultSocketConfig(socketConfig)
+ .setSSLSocketFactory(sf)
+ .setRetryHandler(new HttpRequestRetryHandlerImpl())
+ .build();
} catch (KeyManagementException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
@@ -90,5 +122,52 @@ public static CloseableHttpClient createKeyMaterialHttpClient(KeyStore keystore,
return null;
}
+ public static void setTimeout(int timeout) {
+ HttpClientFactory.timeout = timeout;
+ }
+ public static void setRetryExecutionCount(int retryExecutionCount) {
+ HttpClientFactory.retryExecutionCount = retryExecutionCount;
+ }
+
+
+ /**
+ *
+ * HttpClient 超时重试
+ * @author LiYi
+ */
+ private static class HttpRequestRetryHandlerImpl implements HttpRequestRetryHandler{
+
+ @Override
+ public boolean retryRequest(
+ IOException exception,
+ int executionCount,
+ HttpContext context) {
+ if (executionCount > retryExecutionCount) {
+ return false;
+ }
+ if (exception instanceof InterruptedIOException) {
+ return false;
+ }
+ if (exception instanceof UnknownHostException) {
+ return false;
+ }
+ if (exception instanceof ConnectTimeoutException) {
+ return true;
+ }
+ if (exception instanceof SSLException) {
+ return false;
+ }
+ HttpClientContext clientContext = HttpClientContext.adapt(context);
+ HttpRequest request = clientContext.getRequest();
+ boolean idempotent = !(request instanceof HttpEntityEnclosingRequest);
+ if (idempotent) {
+ // Retry if the request is considered idempotent
+ return true;
+ }
+ return false;
+ }
+
+ };
+
}