我的HttpClients4.3工具类

HttpClients4.3工具类

本工具类应该不是很完善,在我的项目中时常会有一些异常发生(连接重置,响应超时等),可能代码中有一些问题我没有发现。为保证请求绝对提交,可以使用java自带的API(java.net.HttpURLConnection)相结合,外加失败重试任务(视具体业务而定)等方式。
java.net.HttpURLConnection方式的代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
package com.zzcm.fourgad.util;

import org.apache.http.entity.StringEntity;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.util.Map;

public class WebUtil {
private static Logger logger = LoggerFactory.getLogger(WebUtil.class);
/** 响应超时时间 */
private static final int SOCKET_TIMEOUT = 15000;
/** 链接超时时间 */
private static final int CONNECT_TIMEOUT = 10000;

/**
* 向客户端发送信息
* @param response
* @param data
*/

public static void sendData(HttpServletResponse response, String data) {
PrintWriter printWriter = null;
try {
response.setCharacterEncoding("UTF-8");
printWriter = response.getWriter();
printWriter.write(data);
} catch (IOException e) {
e.printStackTrace();
} finally {
if (printWriter != null) {
printWriter.flush();
printWriter.close();
}
}
}

/**
* HttpURLConnection 发送请求
* @author qiulongjie
* @param uri
* @param method
* @param params
* @param encode
* @return
*/

public static String sendData(String uri,String method,String params,String encode){
try {
URL url = new URL(uri);
HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
urlConnection.setConnectTimeout(CONNECT_TIMEOUT);
urlConnection.setReadTimeout(SOCKET_TIMEOUT);
// 设置允许输入输出
urlConnection.setDoInput(true);
urlConnection.setDoOutput(true);
byte[] mydata = params.getBytes();
// 设置请求报文头,设定请求数据类型
urlConnection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
// 设置请求数据长度
urlConnection.setRequestProperty("Content-Length", String.valueOf(mydata.length));
// 设置POST方式请求数据
urlConnection.setRequestMethod(method);
OutputStream outputStream = urlConnection.getOutputStream();
outputStream.write(mydata);
outputStream.flush();
outputStream.close();
int responseCode = urlConnection.getResponseCode();
if (responseCode == 200) {
return changeInputStream(urlConnection.getInputStream(), encode);
}
} catch (IOException e) {
logger.error("sendData url=" + uri + ",method=" + method + ",params=" + params, e);
}
return "";
}

public static String sendJSONData(String uri,String method,String params,String encode){
try {
URL url = new URL(uri);
HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
urlConnection.setConnectTimeout(CONNECT_TIMEOUT);
urlConnection.setReadTimeout(SOCKET_TIMEOUT);
// 设置允许输入输出
urlConnection.setDoInput(true);
urlConnection.setDoOutput(true);
byte[] mydata = params.getBytes();
// 设置请求报文头,设定请求数据类型
urlConnection.setRequestProperty("Content-Type", "application/json");
// 设置请求数据长度
urlConnection.setRequestProperty("Content-Length", String.valueOf(mydata.length));
// 设置POST方式请求数据
urlConnection.setRequestMethod(method);
OutputStream outputStream = urlConnection.getOutputStream();
outputStream.write(mydata);
outputStream.flush();
outputStream.close();
int responseCode = urlConnection.getResponseCode();
if (responseCode == 200) {
return changeInputStream(urlConnection.getInputStream(), encode);
}
} catch (IOException e) {
logger.error("sendJSONData url="+uri+",method="+method+",params="+params,e);
}
return "";
}

/**
* HttpURLConnection 发送请求
* @author qiulongjie
* @param uri
* @param method
* @param params
* @param encode
* @return
*/

public static String sendData(String uri,String method,Map<String,Object> params,String encode,boolean isUrlencode){
StringBuffer buffer = new StringBuffer();
if (params != null && !params.isEmpty()) {
if(isUrlencode){
try {
for (Map.Entry<String, Object> entry : params.entrySet()) {
buffer.append(entry.getKey()).append("=")
.append(URLEncoder.encode(String.valueOf(entry.getValue()),encode))
.append("&");// 请求的参数之间使用&分割。
}
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}else{
for (Map.Entry<String, Object> entry : params.entrySet()) {
buffer.append(entry.getKey()).append("=")
.append(String.valueOf(entry.getValue()))
.append("&");// 请求的参数之间使用&分割。
}
}
buffer.deleteCharAt(buffer.length() - 1);
}
return sendData(uri, method, buffer.toString(), encode);
}

/**
* 把输入流转为字符串
* @author qiulongjie
* @param inputStream
* @param encode
* @return
*/

public static String changeInputStream(InputStream inputStream, String encode) {
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
byte[] data = new byte[1024];
int len = 0;
String result = "";
if (inputStream != null) {
try {
while ((len = inputStream.read(data)) != -1) {
outputStream.write(data, 0, len);
}
result = new String(outputStream.toByteArray(), encode);

} catch (IOException e) {
e.printStackTrace();
} finally {
try {
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return result;
}
}

使用HttpClients方式的代码如下:
maven工程加入依赖

1
2
3
4
5
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.3.1</version>
</dependency>

使用PoolingHttpClientConnectionManager连接池并加入重连策略

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
package com.zzcm.fourgad.util;

import org.apache.commons.lang.StringUtils;
import org.apache.http.Consts;
import org.apache.http.HttpEntity;
import org.apache.http.HttpEntityEnclosingRequest;
import org.apache.http.HttpRequest;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpRequestRetryHandler;
import org.apache.http.client.config.CookieSpecs;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.config.*;
import org.apache.http.conn.ConnectTimeoutException;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.LayeredConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
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.protocol.HttpContext;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.net.ssl.SSLException;
import java.io.IOException;
import java.io.InterruptedIOException;
import java.net.SocketTimeoutException;
import java.net.UnknownHostException;
import java.nio.charset.CodingErrorAction;
import java.util.Map;

public class HttpclientUtil {
private static Logger logger = LoggerFactory.getLogger(HttpclientUtil.class);

/** 重连次数 */
private static final int RETRY_CONNECTION_COUNT = 3;
/** 响应超时时间 */
private static final int SOCKET_TIMEOUT = 15000;
/** 链接超时时间 */
private static final int CONNECT_TIMEOUT = 10000;
/** */
private static final int CONNECT_REQUEST_TIMEOUT = 10000;
/** 连接配置 */
private static RequestConfig requestConfig = null;
/** 重连处理器 */
private static HttpRequestRetryHandler retryHandler = null;
/** 连接管理器 */
private static PoolingHttpClientConnectionManager connManager = null;

private static CloseableHttpClient client = null;

static {
//创建连接配置
requestConfig = RequestConfig.custom().
setCookieSpec(CookieSpecs.BROWSER_COMPATIBILITY).
setSocketTimeout(SOCKET_TIMEOUT).
setConnectTimeout(CONNECT_TIMEOUT).
setConnectionRequestTimeout(CONNECT_REQUEST_TIMEOUT).
setStaleConnectionCheckEnabled(true).
build();

//创建重连处理器
retryHandler = new HttpRequestRetryHandler() {

/**
* exception异常信息;
* executionCount:重连次数;
* context:上下文
*/

public boolean retryRequest(IOException exception, int executionCount,HttpContext context) {

if (executionCount >= RETRY_CONNECTION_COUNT) {//如果连接次数超过RETRY_CONNECTION_COUNT次,就不进行重复连接
logger.warn("尝试"+executionCount+"次失败:--失败的异常:"+exception+"--导致失败的http.request:"+((HttpClientContext) context).getAttribute("http.request").toString());
return false;
}
System.out.println(exception.getClass());
if (exception instanceof SocketTimeoutException) {//响应超时
logger.warn("响应超时--重连接次数:"+executionCount+"--导致重连接的异常:"+exception+"--导致重连接的http.request:"+((HttpClientContext) context).getAttribute("http.request").toString());
return true;
}
if (exception instanceof UnknownHostException) {//未找到主机
logger.warn("未找到主机--重连接次数:"+executionCount+"--导致重连接的异常:"+exception+"--导致重连接的http.request:"+((HttpClientContext) context).getAttribute("http.request").toString());
return true;
}
if (exception instanceof ConnectTimeoutException) {//连接超时
logger.warn("连接超时--重连接次数:"+executionCount+"--导致重连接的异常:"+exception+"--导致重连接的http.request:"+((HttpClientContext) context).getAttribute("http.request").toString());
return true;
}
if (exception instanceof InterruptedIOException) {//io操作中断
logger.warn("io操作中断(响应超时)--重连接次数:"+executionCount+"--导致重连接的异常:"+exception+"--导致重连接的http.request:"+((HttpClientContext) context).getAttribute("http.request").toString());
return true;
}
if (exception instanceof SSLException) {
//SSL handshake exception
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;
}
};

//创建连接管理器
ConnectionSocketFactory plainsf = PlainConnectionSocketFactory.getSocketFactory();
LayeredConnectionSocketFactory sslsf = SSLConnectionSocketFactory.getSocketFactory();
Registry<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory>create()
.register("http", plainsf)
.register("https", sslsf)
.build();
connManager = new PoolingHttpClientConnectionManager(registry);

// Create socket configuration
SocketConfig socketConfig = SocketConfig.custom().setTcpNoDelay(true).build();
connManager.setDefaultSocketConfig(socketConfig);
// Create message constraints
MessageConstraints messageConstraints = MessageConstraints.custom()
.setMaxHeaderCount(200)
.setMaxLineLength(2000)
.build();
// Create connection configuration
ConnectionConfig connectionConfig = ConnectionConfig.custom()
.setMalformedInputAction(CodingErrorAction.IGNORE)
.setUnmappableInputAction(CodingErrorAction.IGNORE)
.setCharset(Consts.UTF_8)
.setMessageConstraints(messageConstraints)
.build();

connManager.setDefaultConnectionConfig(connectionConfig);
// 将最大连接数增加到200
connManager.setMaxTotal(200);
// 将每个路由基础的连接增加到MaxTotal
connManager.setDefaultMaxPerRoute(connManager.getMaxTotal());

client = HttpClients.custom().
setConnectionManager(connManager).
setRetryHandler(retryHandler).
setDefaultRequestConfig(requestConfig).
build();
}

/**
* 发送post请求
* @author qiulongjie
* @param url
* @param params
* @return
*/

public static String postData(String url,Map<String,Object> params){
StringBuffer buffer = new StringBuffer();
if (params != null && !params.isEmpty()) {
for (Map.Entry<String, Object> entry : params.entrySet()) {
buffer.append(entry.getKey()).append("=")
.append(String.valueOf(entry.getValue()))
.append("&");// 请求的参数之间使用&分割。
}
buffer.deleteCharAt(buffer.length() - 1);
}
return postData(url,buffer.toString());
}

/**
* 发送post请求
* @author qiulongjie
* @param url
* @param params
* @return
*/

public static String postData(String url,String params){
StringEntity myEntity = new StringEntity(params,ContentType.create("application/x-www-form-urlencoded", Consts.UTF_8));// 构造请求数据
return postInfo(url, myEntity);
}

/**
* post json数据
* @author qiulongjie
* @param url
* @param json
* @return
*/

public static String postJOSN(String url,String json){
StringEntity myEntity = new StringEntity(json,ContentType.APPLICATION_JSON);// 构造请求数据
return postInfo(url,myEntity);
}

public static String postXML(String url,String xml){
StringEntity myEntity = new StringEntity(xml,ContentType.create("text/xml",Consts.UTF_8));// 构造请求数据
return postInfo(url,myEntity);
}

/**
* 发送post请求
* @author qiulongjie
* @param url
* @param myEntity
* @return
*/

public static String postInfo(String url,StringEntity myEntity){
HttpPost post = new HttpPost(url);
post.setEntity(myEntity);
CloseableHttpResponse response = null;
HttpEntity entity = null;
String result = null;
try {
response = client.execute(post);
if (null != response && response.getStatusLine().getStatusCode() == 200) {
entity = response.getEntity();
result = EntityUtils.toString(entity, "UTF-8");
}
if (null != response && StringUtils.isBlank(result) ) {
logger.error("postInfo response err:" + response.getStatusLine()+",url="+url+",postData="+WebUtil.changeInputStream(myEntity.getContent(),"UTF-8"));
}
EntityUtils.consume(entity);
} catch (ClientProtocolException e) {
logger.error(e.toString(),e);
try {
ExceptionUtil.reportException("post url="+url+",postData="+WebUtil.changeInputStream(myEntity.getContent(),"UTF-8"),e);
} catch (IOException e1) {
logger.error(e.toString(), e);
}
} catch (IOException e) {
logger.error(e.toString(),e);
try {
ExceptionUtil.reportException("post url="+url+",postData="+WebUtil.changeInputStream(myEntity.getContent(),"UTF-8"),e);
} catch (IOException e1) {
logger.error(e.toString(),e);
}
}catch (Exception e) {
logger.error(e.toString(),e);
try {
ExceptionUtil.reportException("post url="+url+",postData="+WebUtil.changeInputStream(myEntity.getContent(),"UTF-8"),e);
} catch (IOException e1) {
logger.error(e.toString(),e);
}
}finally {
// if ( response != null ){
// try {
// response.close();
// } catch (IOException e) {
// logger.error(e.toString(),e);
// }
// }
// post.releaseConnection();
}
if (result == null ){
try {
logger.warn("postInfo result is null ...post url=" + url + ",postData=" + WebUtil.changeInputStream(myEntity.getContent(), "UTF-8"));
} catch (IOException e) {
logger.error(e.toString(),e);
}
}
return result;
}

/**
* 以GET方式发送数据
* @author qiulongjie
* @param url
* @return
*/

public static String sendInfoForGET(String url){
HttpGet get = new HttpGet(url);
CloseableHttpResponse response = null;
HttpEntity entity = null;
String result = null;
try {
response = client.execute(get);
if (null != response && response.getStatusLine().getStatusCode() == 200) {
entity = response.getEntity();
result = EntityUtils.toString(entity, "UTF-8");
}
if (null != response && StringUtils.isBlank(result) ) {
logger.error("sendInfoForGET response err:" + response.getStatusLine() + ",url="+url);
}
EntityUtils.consume(entity);
} catch (ClientProtocolException e) {
logger.error(e.toString(),e);
ExceptionUtil.reportException("get url="+url,e);
} catch (IOException e) {
logger.error(e.toString(),e);
ExceptionUtil.reportException("get url="+url,e);
}catch (Exception e) {
logger.error(e.toString(),e);
ExceptionUtil.reportException("get url="+url,e);
}finally {
// if ( response != null ){
// try {
// response.close();
// } catch (IOException e) {
// logger.error(e.toString(), e);
// }
// }
// get.releaseConnection();
}
if (result == null ){
logger.error("sendInfoForGET result is null ...,url="+url);
}
return result;
}

public static void main(String[] args) {

for (int i =0 ; i < 100 ; i++) {
new Thread(
new Runnable() {
public void run() {
for (int i =0 ; i < 100 ; i++) {
if (i%2==0) {
//System.out.println(postData("http://127.0.0.1:8989/fourgad", data));
sendInfoForGET("http://www.baidu.com");
} else {
sendInfoForGET("http://127.0.0.1:8989/fourgad");
}
}
}
}
).start();
}
}
}

response.close();post.releaseConnection();这里被注释掉了

1
2
3
4
5
6
7
8
//			if ( response != null ){
// try {
// response.close();
// } catch (IOException e) {
// logger.error(e.toString(),e);
// }
// }
// post.releaseConnection();

我经过测试注释掉和不注释掉的情况(main方法里),多个线程多个访问的情况下没有这两句代码运行的更加好,所以我注释掉了。
我的这个工具类代码肯定是有些问题的,如果哪位哥们知道或者有更好的代码,期待您的联系或留言。

热评文章