Skip to content

Commit bb905f6

Browse files
committed
Merge remote-tracking branch 'chan/develop' into develop
2 parents dc91381 + b56973f commit bb905f6

19 files changed

+466
-252
lines changed
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
package me.chanjar.weixin.common.util.http;
2+
3+
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
4+
import org.apache.http.impl.client.CloseableHttpClient;
5+
6+
/**
7+
* httpclient build interface
8+
*/
9+
public interface ApacheHttpClientBuilder {
10+
11+
/**
12+
* 构建httpclient实例
13+
* @return new instance of CloseableHttpClient
14+
*/
15+
CloseableHttpClient build();
16+
17+
/**
18+
* 代理服务器地址
19+
* @param httpProxyHost
20+
* @return
21+
*/
22+
ApacheHttpClientBuilder httpProxyHost(String httpProxyHost);
23+
24+
/**
25+
* 代理服务器端口
26+
* @param httpProxyPort
27+
* @return
28+
*/
29+
ApacheHttpClientBuilder httpProxyPort(int httpProxyPort);
30+
31+
/**
32+
* 代理服务器用户名
33+
* @param httpProxyUsername
34+
* @return
35+
*/
36+
ApacheHttpClientBuilder httpProxyUsername(String httpProxyUsername);
37+
38+
/**
39+
* 代理服务器密码
40+
* @param httpProxyPassword
41+
* @return
42+
*/
43+
ApacheHttpClientBuilder httpProxyPassword(String httpProxyPassword);
44+
45+
/**
46+
* ssl连接socket工厂
47+
* @param sslConnectionSocketFactory
48+
* @return
49+
*/
50+
ApacheHttpClientBuilder sslConnectionSocketFactory(SSLConnectionSocketFactory sslConnectionSocketFactory);
51+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,199 @@
1+
package me.chanjar.weixin.common.util.http;
2+
3+
import me.chanjar.weixin.common.util.StringUtils;
4+
import org.apache.http.annotation.NotThreadSafe;
5+
import org.apache.http.auth.AuthScope;
6+
import org.apache.http.auth.UsernamePasswordCredentials;
7+
import org.apache.http.client.CredentialsProvider;
8+
import org.apache.http.client.HttpRequestRetryHandler;
9+
import org.apache.http.client.config.RequestConfig;
10+
import org.apache.http.config.Registry;
11+
import org.apache.http.config.RegistryBuilder;
12+
import org.apache.http.config.SocketConfig;
13+
import org.apache.http.conn.HttpClientConnectionManager;
14+
import org.apache.http.conn.socket.ConnectionSocketFactory;
15+
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
16+
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
17+
import org.apache.http.impl.client.BasicCredentialsProvider;
18+
import org.apache.http.impl.client.CloseableHttpClient;
19+
import org.apache.http.impl.client.HttpClientBuilder;
20+
import org.apache.http.impl.client.HttpClients;
21+
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
22+
import org.apache.http.protocol.HttpContext;
23+
24+
import java.io.IOException;
25+
import java.util.concurrent.TimeUnit;
26+
27+
/**
28+
* httpclient 连接管理器
29+
*/
30+
@NotThreadSafe
31+
public class DefaultApacheHttpHttpClientBuilder implements ApacheHttpClientBuilder {
32+
private int connectionRequestTimeout = 3000;
33+
private int connectionTimeout = 5000;
34+
private int soTimeout = 5000;
35+
private int idleConnTimeout = 60000;
36+
private int checkWaitTime = 5000;
37+
private int maxConnPerHost = 10;
38+
private int maxTotalConn = 50;
39+
private String userAgent;
40+
private HttpRequestRetryHandler httpRequestRetryHandler = new HttpRequestRetryHandler() {
41+
@Override
42+
public boolean retryRequest(IOException exception, int executionCount, HttpContext context) {
43+
return false;
44+
}
45+
};
46+
private SSLConnectionSocketFactory sslConnectionSocketFactory = SSLConnectionSocketFactory.getSocketFactory();
47+
private PlainConnectionSocketFactory plainConnectionSocketFactory = PlainConnectionSocketFactory.getSocketFactory();
48+
49+
private String httpProxyHost;
50+
private int httpProxyPort;
51+
private String httpProxyUsername;
52+
private String httpProxyPassword;
53+
54+
/**
55+
* 连接管理器
56+
*/
57+
private PoolingHttpClientConnectionManager connectionManager;
58+
/**
59+
* 闲置连接监控线程
60+
*/
61+
private IdleConnectionMonitorThread idleConnectionMonitorThread;
62+
63+
/**
64+
* httpClientBuilder
65+
*/
66+
private HttpClientBuilder httpClientBuilder;
67+
68+
private boolean prepared = false;
69+
70+
private DefaultApacheHttpHttpClientBuilder() {
71+
}
72+
73+
public static DefaultApacheHttpHttpClientBuilder get() {
74+
return new DefaultApacheHttpHttpClientBuilder();
75+
}
76+
77+
public ApacheHttpClientBuilder httpProxyHost(String httpProxyHost) {
78+
this.httpProxyHost = httpProxyHost;
79+
return this;
80+
}
81+
82+
public ApacheHttpClientBuilder httpProxyPort(int httpProxyPort) {
83+
this.httpProxyPort = httpProxyPort;
84+
return this;
85+
}
86+
87+
public ApacheHttpClientBuilder httpProxyUsername(String httpProxyUsername) {
88+
this.httpProxyUsername = httpProxyUsername;
89+
return this;
90+
}
91+
92+
public ApacheHttpClientBuilder httpProxyPassword(String httpProxyPassword) {
93+
this.httpProxyPassword = httpProxyPassword;
94+
return this;
95+
}
96+
97+
public ApacheHttpClientBuilder sslConnectionSocketFactory(SSLConnectionSocketFactory sslConnectionSocketFactory){
98+
this.sslConnectionSocketFactory = sslConnectionSocketFactory;
99+
return this;
100+
}
101+
102+
public IdleConnectionMonitorThread getIdleConnectionMonitorThread() {
103+
return idleConnectionMonitorThread;
104+
}
105+
106+
private void prepare(){
107+
Registry<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory>create()
108+
.register("http", plainConnectionSocketFactory)
109+
.register("https", sslConnectionSocketFactory)
110+
.build();
111+
connectionManager = new PoolingHttpClientConnectionManager(registry);
112+
connectionManager.setMaxTotal(maxTotalConn);
113+
connectionManager.setDefaultMaxPerRoute(maxConnPerHost);
114+
connectionManager.setDefaultSocketConfig(
115+
SocketConfig.copy(SocketConfig.DEFAULT)
116+
.setSoTimeout(soTimeout)
117+
.build()
118+
);
119+
120+
idleConnectionMonitorThread = new IdleConnectionMonitorThread(connectionManager, idleConnTimeout, checkWaitTime);
121+
idleConnectionMonitorThread.setDaemon(true);
122+
idleConnectionMonitorThread.start();
123+
124+
httpClientBuilder = HttpClients.custom()
125+
.setConnectionManager(connectionManager)
126+
.setDefaultRequestConfig(
127+
RequestConfig.custom()
128+
.setSocketTimeout(soTimeout)
129+
.setConnectTimeout(connectionTimeout)
130+
.setConnectionRequestTimeout(connectionRequestTimeout)
131+
.build()
132+
)
133+
.setRetryHandler(httpRequestRetryHandler);
134+
135+
if (StringUtils.isNotBlank(httpProxyHost) && StringUtils.isNotBlank(httpProxyUsername)) {
136+
// 使用代理服务器 需要用户认证的代理服务器
137+
CredentialsProvider credsProvider = new BasicCredentialsProvider();
138+
credsProvider.setCredentials(
139+
new AuthScope(httpProxyHost, httpProxyPort),
140+
new UsernamePasswordCredentials(httpProxyUsername, httpProxyPassword));
141+
httpClientBuilder.setDefaultCredentialsProvider(credsProvider);
142+
}
143+
144+
if (StringUtils.isNotBlank(userAgent)) {
145+
httpClientBuilder.setUserAgent(userAgent);
146+
}
147+
148+
}
149+
150+
public CloseableHttpClient build() {
151+
if(!prepared){
152+
prepare();
153+
prepared = true;
154+
}
155+
156+
return httpClientBuilder.build();
157+
}
158+
159+
public static class IdleConnectionMonitorThread extends Thread {
160+
private final HttpClientConnectionManager connMgr;
161+
private final int idleConnTimeout;
162+
private final int checkWaitTime;
163+
private volatile boolean shutdown;
164+
165+
public IdleConnectionMonitorThread(HttpClientConnectionManager connMgr, int idleConnTimeout, int checkWaitTime) {
166+
super("IdleConnectionMonitorThread");
167+
this.connMgr = connMgr;
168+
this.idleConnTimeout = idleConnTimeout;
169+
this.checkWaitTime = checkWaitTime;
170+
}
171+
172+
@Override
173+
public void run() {
174+
try {
175+
while (!shutdown) {
176+
synchronized (this) {
177+
wait(checkWaitTime);
178+
connMgr.closeExpiredConnections();
179+
connMgr.closeIdleConnections(idleConnTimeout, TimeUnit.MILLISECONDS);
180+
}
181+
}
182+
} catch (InterruptedException ignore) {
183+
}
184+
}
185+
186+
public void trigger() {
187+
synchronized (this) {
188+
notifyAll();
189+
}
190+
}
191+
192+
public void shutdown() {
193+
shutdown = true;
194+
synchronized (this) {
195+
notifyAll();
196+
}
197+
}
198+
}
199+
}

weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/JoddGetRequestExecutor.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ public String execute(CloseableHttpClient httpclient, HttpHost httpProxy, String
3333
if (httpProxy != null) {
3434
ProxyInfo proxyInfoObj = new ProxyInfo(
3535
ProxyInfo.ProxyType.HTTP,
36-
httpProxy.getAddress().getHostAddress(),
36+
httpProxy.getHostName(),
3737
httpProxy.getPort(), "", "");
3838
provider.useProxy(proxyInfoObj);
3939
}

weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/MediaDownloadRequestExecutor.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,8 @@ public File execute(CloseableHttpClient httpclient, HttpHost httpProxy, String u
7474
File localFile = FileUtils.createTmpFile(inputStream, name_ext[0], name_ext[1], tmpDirFile);
7575
return localFile;
7676

77+
}finally {
78+
httpGet.releaseConnection();
7779
}
7880

7981
}

weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/MediaUploadRequestExecutor.java

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
package me.chanjar.weixin.common.util.http;
22

3-
import java.io.File;
4-
import java.io.IOException;
5-
3+
import me.chanjar.weixin.common.bean.result.WxError;
64
import me.chanjar.weixin.common.bean.result.WxMediaUploadResult;
5+
import me.chanjar.weixin.common.exception.WxErrorException;
76
import org.apache.http.HttpEntity;
87
import org.apache.http.HttpHost;
98
import org.apache.http.client.ClientProtocolException;
@@ -13,11 +12,11 @@
1312
import org.apache.http.entity.ContentType;
1413
import org.apache.http.entity.mime.HttpMultipartMode;
1514
import org.apache.http.entity.mime.MultipartEntityBuilder;
16-
17-
import me.chanjar.weixin.common.bean.result.WxError;
18-
import me.chanjar.weixin.common.exception.WxErrorException;
1915
import org.apache.http.impl.client.CloseableHttpClient;
2016

17+
import java.io.File;
18+
import java.io.IOException;
19+
2120
/**
2221
* 上传媒体文件请求执行器,请求的参数是File, 返回的结果是String
2322
* @author Daniel Qian
@@ -48,6 +47,8 @@ public WxMediaUploadResult execute(CloseableHttpClient httpclient, HttpHost http
4847
throw new WxErrorException(error);
4948
}
5049
return WxMediaUploadResult.fromJson(responseContent);
50+
}finally {
51+
httpPost.releaseConnection();
5152
}
5253
}
5354

weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/SimpleGetRequestExecutor.java

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,16 @@
11
package me.chanjar.weixin.common.util.http;
22

3-
import java.io.IOException;
4-
3+
import me.chanjar.weixin.common.bean.result.WxError;
4+
import me.chanjar.weixin.common.exception.WxErrorException;
55
import org.apache.http.HttpHost;
66
import org.apache.http.client.ClientProtocolException;
77
import org.apache.http.client.config.RequestConfig;
88
import org.apache.http.client.methods.CloseableHttpResponse;
99
import org.apache.http.client.methods.HttpGet;
10-
11-
import me.chanjar.weixin.common.bean.result.WxError;
12-
import me.chanjar.weixin.common.exception.WxErrorException;
1310
import org.apache.http.impl.client.CloseableHttpClient;
1411

12+
import java.io.IOException;
13+
1514
/**
1615
* 简单的GET请求执行器,请求的参数是String, 返回的结果也是String
1716
* @author Daniel Qian
@@ -40,6 +39,8 @@ public String execute(CloseableHttpClient httpclient, HttpHost httpProxy, String
4039
throw new WxErrorException(error);
4140
}
4241
return responseContent;
42+
}finally {
43+
httpGet.releaseConnection();
4344
}
4445
}
4546

weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/SimplePostRequestExecutor.java

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,17 @@
11
package me.chanjar.weixin.common.util.http;
22

3-
import java.io.IOException;
4-
53
import me.chanjar.weixin.common.bean.result.WxError;
64
import me.chanjar.weixin.common.exception.WxErrorException;
75
import org.apache.http.Consts;
86
import org.apache.http.HttpHost;
9-
import org.apache.http.auth.AuthScope;
10-
import org.apache.http.auth.UsernamePasswordCredentials;
117
import org.apache.http.client.ClientProtocolException;
12-
import org.apache.http.client.CredentialsProvider;
138
import org.apache.http.client.config.RequestConfig;
149
import org.apache.http.client.methods.CloseableHttpResponse;
15-
import org.apache.http.client.methods.HttpGet;
1610
import org.apache.http.client.methods.HttpPost;
1711
import org.apache.http.entity.StringEntity;
18-
import org.apache.http.impl.client.BasicCredentialsProvider;
1912
import org.apache.http.impl.client.CloseableHttpClient;
20-
import org.apache.http.impl.client.HttpClients;
21-
import org.apache.http.util.EntityUtils;
13+
14+
import java.io.IOException;
2215

2316
/**
2417
* 简单的POST请求执行器,请求的参数是String, 返回的结果也是String
@@ -47,6 +40,8 @@ public String execute(CloseableHttpClient httpclient, HttpHost httpProxy, String
4740
throw new WxErrorException(error);
4841
}
4942
return responseContent;
43+
}finally {
44+
httpPost.releaseConnection();
5045
}
5146
}
5247

weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpConfigStorage.java

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
package me.chanjar.weixin.cp.api;
22

3-
import java.io.File;
4-
53
import me.chanjar.weixin.common.bean.WxAccessToken;
4+
import me.chanjar.weixin.common.util.http.ApacheHttpClientBuilder;
5+
6+
import java.io.File;
67

78
/**
89
* 微信客户端配置存储
@@ -63,4 +64,9 @@ public interface WxCpConfigStorage {
6364

6465
public File getTmpDirFile();
6566

67+
/**
68+
* http client builder
69+
* @return ApacheHttpClientBuilder
70+
*/
71+
public ApacheHttpClientBuilder getApacheHttpClientBuilder();
6672
}

0 commit comments

Comments
 (0)