HttpClient、OkHttp、RestTemplate、WebClient的基本使用

摘要

  • 本文内容基于org.apache.httpcomponents:httpclient:4.5.12,com.squareup.okhttp3:okhttp:4.5.0,springboot:2.2.6.RELEASE,spring-boot-starter-webflux:2.2.6.RELEASE
  • 工具类,实现get/post[参数,json,输入流,文件,gzip]等方法
  • 提供了测试用例及服务端demo
  • github:https://github.com/hanqunfeng/springbootchapter/tree/master/chapter26

HttpClientUtil

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
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
package org.example;

import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
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.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.concurrent.FutureCallback;
import org.apache.http.entity.ByteArrayEntity;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.DefaultHttpRequestRetryHandler;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.nio.client.CloseableHttpAsyncClient;
import org.apache.http.impl.nio.client.HttpAsyncClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;

import java.io.*;
import java.net.URI;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;

/**
* <p>HttpClient工具类</p>
* Created by hanqf on 2020/4/18 14:54.
*/

@Slf4j
public class HttpClientUtil {
/**
* 配置信息
*/
private static final RequestConfig requestConfig = RequestConfig.custom()
// 设置连接超时时间(单位毫秒)
.setConnectTimeout(5000)
// 设置请求超时时间(单位毫秒)
.setConnectionRequestTimeout(5000)
// socket读写超时时间(单位毫秒)
.setSocketTimeout(5000)
// 设置是否允许重定向(默认为true)
.setRedirectsEnabled(true)
//是否启用内容压缩,默认true
.setContentCompressionEnabled(true)
.build();
/**
* 获得Http客户端
*/
private static final CloseableHttpClient HTTP_CLIENT = HttpClientBuilder.create()
.setRetryHandler(new DefaultHttpRequestRetryHandler()) //失败重试,默认3次
.build();

/**
* 异步Http客户端
*/
private static final CloseableHttpAsyncClient HTTP_ASYNC_CLIENT = HttpAsyncClients.custom()
.setDefaultRequestConfig(requestConfig)
.build();


/**
* <p>异步请求</p>
*
* @param httpRequestBase
* @author hanqf
* 2020/4/22 21:16
*/
private static void executeAsync(HttpRequestBase httpRequestBase) {
HTTP_ASYNC_CLIENT.start();
HTTP_ASYNC_CLIENT.execute(httpRequestBase, new FutureCallback<HttpResponse>() {
@SneakyThrows
@Override
public void completed(HttpResponse httpResponse) {
log.info(" callback thread id is : " + Thread.currentThread().getId());
log.info(httpRequestBase.getRequestLine() + "->" + httpResponse.getStatusLine());

StringBuffer stringBuffer = new StringBuffer();
for (Header header : httpRequestBase.getAllHeaders()) {
stringBuffer.append(header.toString()).append(",");
}
log.info(String.format("请求头信息: [%s]", stringBuffer.toString()));


String responseResult = null;
HttpEntity responseEntity = httpResponse.getEntity();
log.debug("响应状态为:" + httpResponse.getStatusLine());
if (responseEntity != null) {
responseResult = EntityUtils.toString(responseEntity, StandardCharsets.UTF_8);
log.info("响应内容为:" + responseResult);

}

stringBuffer = new StringBuffer();
for (Header header : httpResponse.getAllHeaders()) {
stringBuffer.append(header.toString()).append(",");
}
log.info(String.format("响应头信息: [%s]", stringBuffer.toString()));


}

@Override
public void failed(Exception e) {
log.info(" callback thread id is : " + Thread.currentThread().getId());
log.info("Get responseResult:", e);
e.printStackTrace();
}

@Override
public void cancelled() {
log.info(httpRequestBase.getRequestLine() + " cancelled");
}
});
}


/**
* <p>请求的执行方法,需要提前封装好httpRequestBase对象,如请求url和请求参数</p>
*
* @param httpRequestBase
* @return java.lang.String
* @author hanqf
* 2020/4/18 22:08
*/
private static String execute(HttpRequestBase httpRequestBase) {
log.info(String.format("请求地址: [%s]", httpRequestBase.getURI().toString()));
log.info(String.format("请求类型: [%s]", httpRequestBase.getMethod()));

StringBuffer stringBuffer = new StringBuffer();
for (Header header : httpRequestBase.getAllHeaders()) {
stringBuffer.append(header.toString()).append(",");
}
log.info(String.format("请求头信息: [%s]", stringBuffer.toString()));


log.info(String.format("请求参数: [%s]", httpRequestBase.getURI().getQuery()));

String responseResult = null;
// 响应模型
CloseableHttpResponse response = null;
try {
// 将上面的配置信息 运用到这个Get请求里
httpRequestBase.setConfig(requestConfig);
long t1 = System.nanoTime();//请求发起的时间
response = HTTP_CLIENT.execute(httpRequestBase);
// 从响应模型中获取响应实体
HttpEntity responseEntity = response.getEntity();
log.debug("响应状态为:" + response.getStatusLine());
long t2 = System.nanoTime();//收到响应的时间
if (responseEntity != null) {

responseResult = EntityUtils.toString(responseEntity, StandardCharsets.UTF_8);

log.debug("响应内容为:" + responseResult);

}

stringBuffer = new StringBuffer();
for (Header header : response.getAllHeaders()) {
stringBuffer.append(header.toString()).append(",");
}
log.info(String.format("响应头信息: [%s]", stringBuffer.toString()));

log.info(String.format("执行时间: [%.1fms]", (t2 - t1) / 1e6d));

} catch (Exception e) {
log.info("Get responseResult:", e);
e.printStackTrace();
} finally {
try {
if (response != null) {
response.close();
}
} catch (IOException e) {
e.printStackTrace();
}

}
return responseResult;

}

/**
* <p>请求的执行方法,需要提前封装好httpRequestBase对象,如请求url和请求参数</p>
*
* @param httpRequestBase
* @return byte[]
* @author hanqf
* 2020/4/29 13:33
*/
private static byte[] executeBytes(HttpRequestBase httpRequestBase) {
log.info(String.format("请求地址: [%s]", httpRequestBase.getURI().toString()));
log.info(String.format("请求类型: [%s]", httpRequestBase.getMethod()));
StringBuffer stringBuffer = new StringBuffer();
for (Header header : httpRequestBase.getAllHeaders()) {
stringBuffer.append(header.toString()).append(",");
}
log.info(String.format("请求头信息: [%s]", stringBuffer.toString()));


log.info(String.format("请求参数: [%s]", httpRequestBase.getURI().getQuery()));

byte[] bytes = null;
// 响应模型
CloseableHttpResponse response = null;
try {
// 将上面的配置信息 运用到这个Get请求里
httpRequestBase.setConfig(requestConfig);
long t1 = System.nanoTime();//请求发起的时间
response = HTTP_CLIENT.execute(httpRequestBase);
// 从响应模型中获取响应实体
HttpEntity responseEntity = response.getEntity();
log.debug("响应状态为:" + response.getStatusLine());
long t2 = System.nanoTime();//收到响应的时间
if (responseEntity != null) {
bytes = EntityUtils.toByteArray(responseEntity);

//判断是否需要解压,即服务器返回是否经过了gzip压缩--start
Header responseHeader = response.getFirstHeader("Content-Encoding");
if (responseHeader != null && responseHeader.getValue().contains("gzip")) {
GZIPInputStream gzipInputStream = null;
ByteArrayOutputStream out = null;
try {
gzipInputStream = new GZIPInputStream(new ByteArrayInputStream(bytes));
out = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int offset = -1;
while ((offset = gzipInputStream.read(buffer)) != -1) {
out.write(buffer, 0, offset);
}
bytes = out.toByteArray();

} catch (IOException e) {
e.printStackTrace();
} finally {
try {
gzipInputStream.close();
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
//判断是否需要解压,即服务器返回是否经过了gzip压缩--end

log.debug("响应byte长度:" + bytes.length);
}

stringBuffer = new StringBuffer();
for (Header header : response.getAllHeaders()) {
stringBuffer.append(header.toString()).append(",");
}
log.info(String.format("响应头信息: [%s]", stringBuffer.toString()));

log.info(String.format("执行时间: [%.1fms]", (t2 - t1) / 1e6d));

} catch (Exception e) {
log.info("Get responseResult:", e);
e.printStackTrace();
} finally {
try {
if (response != null) {
response.close();
}
} catch (IOException e) {
e.printStackTrace();
}

}
return bytes;

}

/**
* <p>get请求</p>
*
* @param url 请求地址
* @return java.lang.String 响应结果
* @author hanqf
* 2020/4/18 15:57
*/
public static String get(String url) {
return get(url, new HashMap<>());
}

/**
* <p>get请求</p>
*
* @param url 请求地址
* @return java.lang.String 响应结果
* @author hanqf
* 2020/4/18 15:49
*/
public static String get(String url, Map<String, Object> params) {
HttpGet httpGet = null;
List<NameValuePair> list = new ArrayList<>();
for (String key : params.keySet()) {
list.add(new BasicNameValuePair(key, params.get(key).toString()));
}

// 由客户端执行(发送)Get请求
try {
URI uri = new URIBuilder(url).addParameters(list).build();
// 创建Get请求
httpGet = new HttpGet(uri);

} catch (Exception e) {
log.info("Get responseResult:", e);
e.printStackTrace();
}
return execute(httpGet);
}

/**
* <p>get请求,返回字节数组</p>
*
* @param url
* @param params
* @return byte[]
* @author hanqf
* 2020/4/29 13:35
*/
public static byte[] getBytes(String url, Map<String, Object> params) {
HttpGet httpGet = null;
List<NameValuePair> list = new ArrayList<>();
for (String key : params.keySet()) {
list.add(new BasicNameValuePair(key, params.get(key).toString()));
}

// 由客户端执行(发送)Get请求
try {
URI uri = new URIBuilder(url).addParameters(list).build();
// 创建Get请求
httpGet = new HttpGet(uri);

} catch (Exception e) {
log.info("Get responseResult:", e);
e.printStackTrace();
}
return executeBytes(httpGet);
}

/**
* <p>post请求</p>
*
* @param url 请求地址
* @return java.lang.String 响应结果
* @author hanqf
* 2020/4/18 15:54
*/
public static String post(String url) {
return post(url, new HashMap<>());
}

/**
* <p>post请求</p>
*
* @param url 请求地址
* @param params 请求参数
* @return java.lang.String 响应结果
* @author hanqf
* 2020/4/18 15:50
*/
public static String post(String url, Map<String, Object> params) {
HttpPost httpPost = null;
List<NameValuePair> list = new ArrayList<>();
for (String key : params.keySet()) {
list.add(new BasicNameValuePair(key, params.get(key).toString()));
}

try {
URI uri = new URIBuilder(url).addParameters(list).build();
httpPost = new HttpPost(uri);
} catch (Exception e) {
log.info("Get responseResult:", e);
e.printStackTrace();
}

return execute(httpPost);
}

/**
* <p>post请求,返回字节数组</p>
*
* @param url
* @param params
* @return byte[]
* @author hanqf
* 2020/4/29 13:35
*/
public static byte[] postBytes(String url, Map<String, Object> params) {
HttpPost httpPost = null;
List<NameValuePair> list = new ArrayList<>();
for (String key : params.keySet()) {
list.add(new BasicNameValuePair(key, params.get(key).toString()));
}

try {
URI uri = new URIBuilder(url).addParameters(list).build();
httpPost = new HttpPost(uri);
} catch (Exception e) {
log.info("Get responseResult:", e);
e.printStackTrace();
}

return executeBytes(httpPost);
}

/**
* <p>post请求,请求体为json</p>
*
* @param url 请求地址
* @param json 请求json
* @return java.lang.String 响应结果
* @author hanqf
* 2020/4/18 16:02
*/
public static String postJson(String url, String json) {
return postJson(url, json, false);
}

/**
* <p>post请求,请求体为json</p>
*
* @param url 请求地址
* @param json 请求json
* @param gzip 是否开启gzip压缩
* @return java.lang.String 响应结果
* @author hanqf
* 2020/4/18 16:02
*/
public static String postJson(String url, String json, boolean gzip) {
HttpPost httpPost = null;
try {
URI uri = new URIBuilder(url).build();
httpPost = new HttpPost(uri);

// post请求是将参数放在请求体里面传过去的,这里将entity放入post请求体中

httpPost.setHeader("Content-Type", "application/json;charset=utf8");

if (gzip) {
httpPost.setHeader("Content-Encoding", "gzip");
ByteArrayOutputStream originalContent = new ByteArrayOutputStream();
originalContent.write(json.getBytes(StandardCharsets.UTF_8));
ByteArrayOutputStream baos = new ByteArrayOutputStream();
GZIPOutputStream gzipOut = new GZIPOutputStream(baos);
originalContent.writeTo(gzipOut);
gzipOut.finish();
httpPost.setEntity(new ByteArrayEntity(baos
.toByteArray(), ContentType.create("text/plain", "utf-8")));
} else {
StringEntity entity = new StringEntity(json, "UTF-8");
httpPost.setEntity(entity);

}

} catch (Exception e) {
log.info("Get responseResult:", e);
e.printStackTrace();
}
return execute(httpPost);
}

/**
* <p>post请求,请求参数中有中文的话可以使用这个请求</p>
*
* @param url 请求地址
* @param params 请求参数,只可以为中文
* @return java.lang.String
* @author hanqf
* 2020/4/18 16:30
*/
public static String postForm(String url, Map<String, Object> params) {
HttpPost httpPost = null;
List<NameValuePair> list = new ArrayList<>();
for (String key : params.keySet()) {
list.add(new BasicNameValuePair(key, params.get(key).toString()));
}

try {
UrlEncodedFormEntity urlEncodedFormEntity = new UrlEncodedFormEntity(list, StandardCharsets.UTF_8);
URI uri = new URIBuilder(url).build();
httpPost = new HttpPost(uri);
httpPost.setHeader("Content-Type", "application/x-www-form-urlencoded");
httpPost.setEntity(urlEncodedFormEntity);


} catch (Exception e) {
log.info("Get responseResult:", e);
e.printStackTrace();
}

return execute(httpPost);
}

/**
* <p>post请求,输入流</p>
*
* @param url 请求地址
* @param bytes 请求输入流
* @return java.lang.String
* @author hanqf
* 2020/4/18 16:37
*/
public static String postInputBytes(String url, byte[] bytes) {
return postInputBytes(url, bytes, false);
}

/**
* <p>post请求,输入流</p>
*
* @param url 请求地址
* @param bytes 请求输入流
* @param gzip 是否开启gzip压缩
* @return java.lang.String
* @author hanqf
* 2020/4/18 16:37
*/
public static String postInputBytes(String url, byte[] bytes, boolean gzip) {
HttpPost httpPost = null;
try {
URI uri = new URIBuilder(url).build();
httpPost = new HttpPost(uri);

// post请求是将参数放在请求体里面传过去的,这里将entity放入post请求体中
if (gzip) {
httpPost.setHeader("Content-Encoding", "gzip");
ByteArrayOutputStream originalContent = new ByteArrayOutputStream();
originalContent.write(bytes);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
GZIPOutputStream gzipOut = new GZIPOutputStream(baos);
originalContent.writeTo(gzipOut);
gzipOut.finish();
httpPost.setEntity(new ByteArrayEntity(baos
.toByteArray(), ContentType.create("text/plain", "utf-8")));
} else {
ByteArrayEntity entity = new ByteArrayEntity(bytes, ContentType.create("text/plain", "utf-8"));
httpPost.setEntity(entity);
}

} catch (Exception e) {
log.info("Get responseResult:", e);
e.printStackTrace();
}

return execute(httpPost);
}

/**
* <p>post请求,流</p>
*
* @param url
* @param is
* @return java.lang.String
* @author hanqf
* 2020/4/21 22:24
*/
public static String postInputStream(String url, InputStream is) {
return postInputStream(url, is, false);
}

/**
* <p>post请求,流</p>
*
* @param url
* @param is
* @param gzip
* @return java.lang.String
* @author hanqf
* 2020/4/21 22:24
*/
public static String postInputStream(String url, InputStream is, boolean gzip) {
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int ch;
byte[] bytes = null;
try {
while ((ch = is.read(buffer)) != -1) {
byteArrayOutputStream.write(buffer, 0, ch);
}
bytes = byteArrayOutputStream.toByteArray();
byteArrayOutputStream.close();
} catch (Exception e) {
e.printStackTrace();
}
return postInputBytes(url, bytes, gzip);
}

/**
* <p>post请求,传输附件</p>
*
* @param url 请求地址
* @param files 文件列表
* @return java.lang.String
* @author hanqf
* 2020/4/18 16:52
*/
public static String postFile(String url, File[] files) {
return postFile(url, new HashMap<>(), files);
}

/**
* <p>post请求,传输附件</p>
*
* @param url 请求地址
* @param params 其它参数
* @param files 文件列表
* @return java.lang.String
* @author hanqf
* 2020/4/18 16:50
*/
public static String postFile(String url, Map<String, Object> params, File[] files) {
HttpPost httpPost = null;
try {
URI uri = new URIBuilder(url).build();
httpPost = new HttpPost(uri);

MultipartEntityBuilder multipartEntityBuilder = MultipartEntityBuilder.create();
String filesKey = "files";
for (File file : files) {
//multipartEntityBuilder.addPart(filesKey,new FileBody(file)); //与下面的语句作用相同
//multipartEntityBuilder.addBinaryBody(filesKey, file);

// 防止服务端收到的文件名乱码。 我们这里可以先将文件名URLEncode,然后服务端拿到文件名时在URLDecode。就能避免乱码问题。
// 文件名其实是放在请求头的Content-Disposition里面进行传输的,如其值为form-data; name="files"; filename="头像.jpg"
multipartEntityBuilder.addBinaryBody(filesKey, file, ContentType.DEFAULT_BINARY, URLEncoder.encode(file.getName(), "utf-8"));

}

// 其它参数(注:自定义contentType,设置UTF-8是为了防止服务端拿到的参数出现乱码)
ContentType contentType = ContentType.create("text/plain", StandardCharsets.UTF_8);
for (String key : params.keySet()) {
multipartEntityBuilder.addTextBody(key, params.get(key).toString(), contentType);
}
HttpEntity entity = multipartEntityBuilder.build();

// post请求是将参数放在请求体里面传过去的,这里将entity放入post请求体中
httpPost.setEntity(entity);

} catch (Exception e) {
log.info("Get responseResult:", e);
e.printStackTrace();
}

return execute(httpPost);
}


}

OkHttpUtil

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
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
package org.example;


import com.alibaba.fastjson.JSONArray;
import lombok.extern.slf4j.Slf4j;
import okhttp3.*;
import okio.BufferedSink;
import okio.GzipSink;
import okio.Okio;
import org.jetbrains.annotations.NotNull;

import java.io.*;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
import java.util.zip.GZIPInputStream;

/**
* <p>OkHttp工具类</p>
* Created by hanqf on 2020/4/18 21:54.
*/

@Slf4j
public class OkHttpUtil {

/**
* 获得OkHttpClient客户端
*/
private static final OkHttpClient client = new OkHttpClient.Builder()
.connectTimeout(5L, TimeUnit.SECONDS) //连接超时时间,5秒
.readTimeout(5L, TimeUnit.SECONDS) //读超时时间,5秒
.writeTimeout(5L, TimeUnit.SECONDS) //写超时时间,5秒
.followRedirects(true) //设置是否允许重定向,默认true
//注意拦截器的顺序
.addInterceptor(new GzipRequestInterceptor()) //开启gzip压缩,支持对流或Json进行gzip压缩,服务端需要支持解压缩
.addInterceptor(new RetryIntercepter()) //重试拦截器,默认3次
.addInterceptor(new HeadersLoggingInterceper()) //header拦截器
.build();


/**
* <p>异步调用</p>
* @author hanqf
* 2020/4/22 20:37
* @param request
*/
private static void executeAsync(Request request){
Call call = client.newCall(request);
call.enqueue(new Callback() {
@Override
public void onFailure(@NotNull Call call, @NotNull IOException e) {
log.info("Get responseResult:", e);
e.printStackTrace();
}

@Override
public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException {
String responseResult = null;
if (response.isSuccessful()) {
responseResult = Objects.requireNonNull(response.body()).string();
}
Headers headers = response.headers();
StringBuilder stringBuffer = new StringBuilder();
for(int i=0;i<headers.size();i++){
stringBuffer.append(headers.name(i)).append(":").append(headers.value(i)).append(",");
}
log.info(String.format("响应头信息: [%s]", stringBuffer.toString()));
log.info(String.format("响应结果:%s",responseResult));
}
});
}

/**
* <p>请求的执行方法,需要提前封装好Request对象,如请求url和请求参数</p>
*
* @param request
* @return java.lang.String
* @author hanqf
* 2020/4/18 23:47
*/
private static String execute(Request request) {
String responseResult = null;
try {
long t1 = System.nanoTime();//请求发起的时间
Response response = client.newCall(request).execute();
if (response.isSuccessful()) {
responseResult = Objects.requireNonNull(response.body()).string();
//byte[] bytes = response.body().bytes();
//responseResult = new String(bytes,"utf-8");
}
long t2 = System.nanoTime();//收到响应的时间
Headers headers = response.headers();

StringBuilder stringBuffer = new StringBuilder();
for(int i=0;i<headers.size();i++){
stringBuffer.append(headers.name(i)).append(":").append(headers.value(i)).append(",");
}
log.info(String.format("响应头信息: [%s]", stringBuffer.toString()));

log.info(String.format("执行时间: [%.1fms]", (t2 - t1) / 1e6d));
} catch (IOException e) {
log.info("Get responseResult:", e);
e.printStackTrace();
}
return responseResult;

}

private static byte[] executeBytes(Request request) {
byte[] bytes = null;
try {
long t1 = System.nanoTime();//请求发起的时间
Response response = client.newCall(request).execute();
if (response.isSuccessful()) {
bytes = Objects.requireNonNull(response.body()).bytes();

//判断是否需要解压,即服务器返回是否经过了gzip压缩--start
String responseHeader = response.header("Content-Encoding");
if (responseHeader != null && responseHeader.contains("gzip")) {
GZIPInputStream gzipInputStream = null;
ByteArrayOutputStream out = null;
try {
gzipInputStream = new GZIPInputStream(new ByteArrayInputStream(bytes));
out = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int offset = -1;
while ((offset = gzipInputStream.read(buffer)) != -1) {
out.write(buffer, 0, offset);
}
bytes = out.toByteArray();

} catch (IOException e) {
e.printStackTrace();
} finally {
try {
gzipInputStream.close();
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
//判断是否需要解压,即服务器返回是否经过了gzip压缩--end

}
long t2 = System.nanoTime();//收到响应的时间
Headers headers = response.headers();
StringBuilder stringBuffer = new StringBuilder();
for(int i=0;i<headers.size();i++){
stringBuffer.append(headers.name(i)).append(":").append(headers.value(i)).append(",");
}
log.info(String.format("响应头信息: [%s]", stringBuffer.toString()));

log.info(String.format("执行时间: [%.1fms]", (t2 - t1) / 1e6d));
} catch (IOException e) {
log.info("Get responseResult:", e);
e.printStackTrace();
}
return bytes;

}

/**
* <p>get请求</p>
*
* @param url 请求url
* @return java.lang.String
* @author hanqf
* 2020/4/18 23:48
*/
public static String get(String url) {
return get(url, new HashMap<>());

}

/**
* <p>get请求</p>
*
* @param url
* @param params
* @return java.lang.String
* @author hanqf
* 2020/4/20 16:40
*/
public static String get(String url, Map<String, Object> params) {
if (params.size() > 0) {
StringBuilder stringBuffer = new StringBuilder();
stringBuffer.append(url);
if (url.contains("?")) {
stringBuffer.append("&");
} else {
stringBuffer.append("?");
}
for (String key : params.keySet()) {
stringBuffer.append(key).append("=").append(params.get(key).toString()).append("&");
}
url = stringBuffer.toString();
}

Request request = new Request.Builder()
.url(url)
.get()
.build();
log.info(String.format("请求地址: [%s]", request.url()));
if (params.size() > 0) {
JSONArray jArray = new JSONArray();
jArray.add(params);
log.info(String.format("请求参数: %s", jArray.toJSONString()));
}

//executeAsync(request);
return execute(request);

}

public static byte[] getBytes(String url, Map<String, Object> params) {
if (params.size() > 0) {
StringBuilder stringBuffer = new StringBuilder();
stringBuffer.append(url);
if (url.contains("?")) {
stringBuffer.append("&");
} else {
stringBuffer.append("?");
}
for (String key : params.keySet()) {
stringBuffer.append(key).append("=").append(params.get(key).toString()).append("&");
}
url = stringBuffer.toString();
}

Request request = new Request.Builder()
.url(url)
.get()
.build();
log.info(String.format("请求地址: [%s]", request.url()));
if (params.size() > 0) {
JSONArray jArray = new JSONArray();
jArray.add(params);
log.info(String.format("请求参数: %s", jArray.toJSONString()));
}

return executeBytes(request);

}

/**
* <p>post请求</p>
*
* @param url 请求url
* @return java.lang.String
* @author hanqf
* 2020/4/18 23:48
*/
public static String post(String url) {
return post(url, new HashMap<>());
}

/**
* <p>post请求</p>
* form请求
*
* @param url 请求url
* @param params 请求参数
* @return java.lang.String
* @author hanqf
* 2020/4/18 23:49
*/
public static String post(String url, Map<String, Object> params) {
//请求头会加入:application/x-www-form-urlencoded
FormBody.Builder builder = new FormBody.Builder();
for (String key : params.keySet()) {
builder.add(key, params.get(key).toString());
}
RequestBody requestBody = builder.build();
Request request = new Request.Builder()
.url(url)
.post(requestBody)
.build();

log.info(String.format("请求地址: [%s]", request.url()));
if (params.size() > 0) {
JSONArray jArray = new JSONArray();
jArray.add(params);
log.info(String.format("请求参数: %s", jArray.toJSONString()));
}
log.info(String.format("请求类型: %s", Objects.requireNonNull(Objects.requireNonNull(request.body()).contentType()).toString()));

return execute(request);

}

public static byte[] postBytes(String url, Map<String, Object> params) {
//请求头会加入:application/x-www-form-urlencoded
FormBody.Builder builder = new FormBody.Builder();
for (String key : params.keySet()) {
builder.add(key, params.get(key).toString());
}
RequestBody requestBody = builder.build();
Request request = new Request.Builder()
.url(url)
.post(requestBody)
.build();

log.info(String.format("请求地址: [%s]", request.url()));
if (params.size() > 0) {
JSONArray jArray = new JSONArray();
jArray.add(params);
log.info(String.format("请求参数: %s", jArray.toJSONString()));
}
log.info(String.format("请求类型: %s", Objects.requireNonNull(Objects.requireNonNull(request.body()).contentType()).toString()));

return executeBytes(request);

}


/**
* <p>post请求,json请求</p>
*
* @param url 请求url
* @param json json数据
* @return java.lang.String
* @author hanqf
* 2020/4/18 23:50
*/
public static String post(String url, String json) {

MediaType mediaType = MediaType.parse("application/json; charset=utf8");
RequestBody requestBody = RequestBody.create(json, mediaType);
Request request = new Request.Builder()
.url(url)
.post(requestBody)
.build();
log.info(String.format("请求地址: [%s]", request.url()));
log.info(String.format("请求参数: %s", json));
log.info(String.format("请求类型: %s", Objects.requireNonNull(Objects.requireNonNull(request.body()).contentType()).toString()));
return execute(request);
}

/**
* <p>post请求,字节流</p>
*
* @param url 请求url
* @param bytes 字节数组
* @return java.lang.String
* @author hanqf
* 2020/4/18 23:51
*/
public static String post(String url, byte[] bytes) {

MediaType mediaType = MediaType.parse("application/octet-stream");
RequestBody requestBody = null;
requestBody = RequestBody.create(bytes, mediaType);

Request request = new Request.Builder()
.url(url)
.post(requestBody)
.build();
log.info(String.format("请求地址: [%s]", request.url()));
log.info(String.format("请求类型: %s", Objects.requireNonNull(Objects.requireNonNull(request.body()).contentType()).toString()));
return execute(request);
}

/**
* <p>post请求,字节流</p>
*
* @param url
* @param is
* @return java.lang.String
* @author hanqf
* 2020/4/21 22:45
*/
public static String post(String url, InputStream is) {
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int ch;
byte[] bytes = null;
try {
while ((ch = is.read(buffer)) != -1) {
byteArrayOutputStream.write(buffer, 0, ch);
}
bytes = byteArrayOutputStream.toByteArray();
byteArrayOutputStream.close();
} catch (Exception e) {
e.printStackTrace();
}
return post(url, bytes);
}

/**
* <p>post请求,文件传输</p>
*
* @param url 请求url
* @param files 文件列表
* @return java.lang.String
* @author hanqf
* 2020/4/18 23:52
*/
public static String post(String url, File[] files) {
return post(url, new HashMap<>(), files);
}

/**
* <p>post请求,文件传输</p>
*
* @param url 请求url
* @param params 参数map
* @param files 文件列表
* @return java.lang.String
* @author hanqf
* 2020/4/18 23:52
*/
public static String post(String url, Map<String, Object> params, File[] files) {

MultipartBody.Builder builder = new MultipartBody.Builder()
.setType(MultipartBody.FORM);
int i = 1;
try {
String filesKey = "files";
for (File file : files) {
//URLEncoder.encode(file.getName(), "utf-8") //中文文件名使用encode,服务端使用decode解析
builder.addFormDataPart(filesKey, URLEncoder.encode(file.getName(), "utf-8"),
RequestBody.create(file, MediaType.parse("multipart/form-data")));
i++;
}

for (String key : params.keySet()) {
builder.addFormDataPart(key, params.get(key).toString());
}

} catch (Exception e) {
e.printStackTrace();
}

RequestBody requestBody = builder.build();
Request request = new Request.Builder()
.url(url)
.post(requestBody)
.build();

log.info(String.format("请求地址: [%s]", request.url()));
if (params != null && params.size() > 0) {
JSONArray jArray = new JSONArray();
jArray.add(params);
log.info(String.format("请求参数: %s", jArray.toJSONString()));
}
if (files != null && files.length > 0) {
JSONArray jArray = new JSONArray();
jArray.add(files);
log.info(String.format("请求参数: %s", jArray.toJSONString()));
}
log.info(String.format("请求类型: %s", Objects.requireNonNull(Objects.requireNonNull(request.body()).contentType()).toString()));
return execute(request);
}


/**
* This interceptor compresses the HTTP request body. Many webservers can't handle this!
*/
private static class GzipRequestInterceptor implements Interceptor {
@NotNull
@Override
public Response intercept(Chain chain) throws IOException {
Request originalRequest = chain.request();
if (originalRequest.body() == null || originalRequest.header("Content-Encoding") != null) {
return chain.proceed(originalRequest);
}

MediaType mediaType = Objects.requireNonNull(originalRequest.body()).contentType();
//对流和json开启压缩
if (mediaType != null && ("application/octet-stream".equals(mediaType.toString()) || "application/json; charset=utf8".equals(mediaType.toString()))) {
Request compressedRequest = originalRequest.newBuilder()
.header("Content-Encoding", "gzip")
.method(originalRequest.method(), gzip(originalRequest.body()))
.build();
return chain.proceed(compressedRequest);
}
return chain.proceed(originalRequest);
}


private RequestBody gzip(final RequestBody body) {
return new RequestBody() {
@Override
public MediaType contentType() {
return body.contentType();
}

@Override
public long contentLength() {
return -1; // We don't know the compressed length in advance!
}

@Override
public void writeTo(@NotNull BufferedSink sink) throws IOException {
BufferedSink gzipSink = Okio.buffer(new GzipSink(sink));
body.writeTo(gzipSink);
gzipSink.close();
}
};
}
}

/**
* <p>重试拦截器</p>
*/
private static class RetryIntercepter implements Interceptor {

private int maxRetry = 3;//最大重试次数,默认3次
private int retryNum = 0;

public RetryIntercepter() {

}

public RetryIntercepter(int maxRetry) {
this.maxRetry = maxRetry;
}

@NotNull
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
Response response = chain.proceed(request);
while (!response.isSuccessful() && retryNum < maxRetry) {
retryNum++;
response = chain.proceed(request);
}
return response;
}
}

/**
* <p>Headers拦截器</p>
*/
private static class HeadersLoggingInterceper implements Interceptor {
@NotNull
@Override
public Response intercept(@NotNull Chain chain) throws IOException {
Request request = chain.request();
Headers headers = request.headers();
StringBuilder stringBuffer = new StringBuilder();
for(int i=0;i<headers.size();i++){
stringBuffer.append(headers.name(i)).append(":").append(headers.value(i)).append(",");
}
log.info(String.format("请求头信息: [%s]", stringBuffer.toString()));
return chain.proceed(request);
}
}
}

RestTemplateUtil

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
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
package org.example;

import lombok.extern.slf4j.Slf4j;
import org.springframework.core.io.FileSystemResource;
import org.springframework.http.*;
import org.springframework.http.client.ClientHttpRequestExecution;
import org.springframework.http.client.ClientHttpRequestInterceptor;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.http.client.SimpleClientHttpRequestFactory;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;

import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;

/**
* <p>RestTemplate工具类</p>
* Created by hanqf on 2020/4/22 16:54.
*/

@Slf4j
public class RestTemplateUtil {

private static final SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();
private static final RestTemplate restTemplate;

static {
factory.setReadTimeout(5000);//单位为ms
factory.setConnectTimeout(5000);//单位为ms

//拦截器
List<ClientHttpRequestInterceptor> list = new ArrayList<>();
list.add(new RetryIntercepter()); //重试拦截器
list.add(new HeadersLoggingInterceper()); //header拦截器

restTemplate = new RestTemplate(factory);
restTemplate.setInterceptors(list);
}

public static String get(String url) {
return get(url, new HashMap<>());
}

/**
* <p>get请求</p>
*
* @param url
* @param map
* @return java.lang.String
* @author hanqf
* 2020/4/22 16:57
*/
public static String get(String url, Map<String, Object> map) {
if (map.size() > 0) {
StringBuilder stringBuffer = new StringBuilder();
stringBuffer.append(url);
if (url.contains("?")) {
stringBuffer.append("&");
} else {
stringBuffer.append("?");
}
for (String key : map.keySet()) {
stringBuffer.append(key).append("=").append(map.get(key).toString()).append("&");
}
url = stringBuffer.toString();
}
return restTemplate.getForObject(url, String.class);
}

public static byte[] getBytes(String url, Map<String, Object> map) {
if (map.size() > 0) {
StringBuilder stringBuffer = new StringBuilder();
stringBuffer.append(url);
if (url.contains("?")) {
stringBuffer.append("&");
} else {
stringBuffer.append("?");
}
for (String key : map.keySet()) {
stringBuffer.append(key).append("=").append(map.get(key).toString()).append("&");
}
url = stringBuffer.toString();
}
//return restTemplate.getForObject(url, byte[].class);
ResponseEntity<byte[]> exchange = restTemplate.exchange(url, HttpMethod.GET, null, byte[].class);
byte[] bytes = exchange.getBody();


//判断是否需要解压,即服务器返回是否经过了gzip压缩--start
List<String> strings = exchange.getHeaders().get("Content-Encoding");
if (strings != null && strings.contains("gzip")) {
GZIPInputStream gzipInputStream = null;
ByteArrayOutputStream out = null;
try {
gzipInputStream = new GZIPInputStream(new ByteArrayInputStream(bytes));
out = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int offset = -1;
while ((offset = gzipInputStream.read(buffer)) != -1) {
out.write(buffer, 0, offset);
}
bytes = out.toByteArray();

} catch (IOException e) {
e.printStackTrace();
} finally {
try {
gzipInputStream.close();
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
//判断是否需要解压,即服务器返回是否经过了gzip压缩--end

return bytes;

}

public static String post(String url) {
return post(url, new HashMap<>());
}

/**
* <p>post请求</p>
*
* @param url
* @param params
* @return java.lang.String
* @author hanqf
* 2020/4/22 16:59
*/
public static String post(String url, Map<String, Object> params) {

MultiValueMap<String, Object> map = new LinkedMultiValueMap<>();
if (params != null && params.size() > 0) {
map.setAll(params);
}

HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
HttpEntity<MultiValueMap<String, Object>> httpEntity = new HttpEntity<>(map, headers);
return restTemplate.postForObject(url, httpEntity, String.class);
}

public static byte[] postBytes(String url, Map<String, Object> params) {

MultiValueMap<String, Object> map = new LinkedMultiValueMap<>();
if (params != null && params.size() > 0) {
map.setAll(params);
}

HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
HttpEntity<MultiValueMap<String, Object>> httpEntity = new HttpEntity<>(map, headers);
//byte[] bytes = restTemplate.postForObject(url, httpEntity, byte[].class);

ResponseEntity<byte[]> exchange = restTemplate.exchange(url, HttpMethod.POST, httpEntity, byte[].class);
byte[] bytes = exchange.getBody();


//判断是否需要解压,即服务器返回是否经过了gzip压缩--start
List<String> strings = exchange.getHeaders().get("Content-Encoding");
if (strings != null && strings.contains("gzip")) {
GZIPInputStream gzipInputStream = null;
ByteArrayOutputStream out = null;
try {
gzipInputStream = new GZIPInputStream(new ByteArrayInputStream(bytes));
out = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int offset = -1;
while ((offset = gzipInputStream.read(buffer)) != -1) {
out.write(buffer, 0, offset);
}
bytes = out.toByteArray();

} catch (IOException e) {
e.printStackTrace();
} finally {
try {
gzipInputStream.close();
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
//判断是否需要解压,即服务器返回是否经过了gzip压缩--end

return bytes;
}

public static String postJson(String url, String json) {
return postJson(url, json, false);
}

/**
* <p>post请求json</p>
*
* @param url
* @param json
* @return java.lang.String
* @author hanqf
* 2020/4/22 17:04
*/
public static String postJson(String url, String json, boolean gzip) {
HttpHeaders headers = new HttpHeaders();


if (gzip) {
headers.setContentType(new MediaType("application", "octet-stream"));
HttpEntity<byte[]> httpEntity = null;
try {
headers.add("Content-Encoding", "gzip");
ByteArrayOutputStream originalContent = new ByteArrayOutputStream();
originalContent.write(json.getBytes(StandardCharsets.UTF_8));
ByteArrayOutputStream baos = new ByteArrayOutputStream();
GZIPOutputStream gzipOut = new GZIPOutputStream(baos);
originalContent.writeTo(gzipOut);
gzipOut.finish();
httpEntity = new HttpEntity<>(baos.toByteArray(), headers);
} catch (Exception e) {
e.printStackTrace();
}
return restTemplate.postForObject(url, httpEntity, String.class);
} else {
headers.setContentType(new MediaType("application", "json", StandardCharsets.UTF_8));
//headers.add("Content-Type", "application/json;charset=utf8");
HttpEntity<String> httpEntity = new HttpEntity<>(json, headers);
return restTemplate.postForObject(url, httpEntity, String.class);
}
}

public static String postBytes(String url, byte[] bytes) {
return postBytes(url, bytes, false);
}

/**
* <p>post字节流</p>
*
* @param url
* @param bytes
* @param gzip
* @return java.lang.String
* @author hanqf
* 2020/4/22 17:10
*/
public static String postBytes(String url, byte[] bytes, boolean gzip) {
HttpHeaders headers = new HttpHeaders();
headers.setContentType(new MediaType("application", "octet-stream"));
HttpEntity<byte[]> httpEntity = null;
if (gzip) {
try {
headers.add("Content-Encoding", "gzip");
ByteArrayOutputStream originalContent = new ByteArrayOutputStream();
originalContent.write(bytes);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
GZIPOutputStream gzipOut = new GZIPOutputStream(baos);
originalContent.writeTo(gzipOut);
gzipOut.finish();
httpEntity = new HttpEntity<>(baos.toByteArray(), headers);
} catch (Exception e) {
e.printStackTrace();
}

} else {
httpEntity = new HttpEntity<>(bytes, headers);
}
return restTemplate.postForObject(url, httpEntity, String.class);

}

public static String postStream(String url, InputStream is) {
return postStream(url, is, false);
}

/**
* <p>post请求,流</p>
*
* @param url
* @param is
* @param gzip
* @return java.lang.String
* @author hanqf
* 2020/4/22 17:12
*/
public static String postStream(String url, InputStream is, boolean gzip) {
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int ch;
byte[] bytes = null;
try {
while ((ch = is.read(buffer)) != -1) {
byteArrayOutputStream.write(buffer, 0, ch);
}
bytes = byteArrayOutputStream.toByteArray();
byteArrayOutputStream.close();
} catch (Exception e) {
e.printStackTrace();
}

return postBytes(url, bytes, gzip);

}

public static String postFiles(String url, File[] files) {
return postFiles(url, new HashMap<>(), files);
}

/**
* <p>post请求,传输文件</p>
*
* @param url
* @param params
* @param files
* @return java.lang.String
* @author hanqf
* 2020/4/22 17:16
*/
public static String postFiles(String url, Map<String, Object> params, File[] files) {

MultiValueMap<String, Object> map = new LinkedMultiValueMap<>();
if (params != null && params.size() > 0) {
map.setAll(params);
}

for (File file : files) {
map.add("files", new FileSystemResource(file));
}
return restTemplate.postForObject(url, map, String.class);

}

/**
* <p>重试拦截器</p>
*/
private static class RetryIntercepter implements ClientHttpRequestInterceptor {

private int maxRetry = 3;//最大重试次数,默认3次
private int retryNum = 0;

public RetryIntercepter() {

}

public RetryIntercepter(int maxRetry) {
this.maxRetry = maxRetry;
}

@Override
public ClientHttpResponse intercept(HttpRequest httpRequest, byte[] bytes, ClientHttpRequestExecution clientHttpRequestExecution) throws IOException {
ClientHttpResponse response = clientHttpRequestExecution.execute(httpRequest, bytes);
if (!response.getStatusCode().equals(HttpStatus.OK) && retryNum < maxRetry) {
retryNum++;
response = clientHttpRequestExecution.execute(httpRequest, bytes);

}
return response;
}
}

/**
* <p>Headers拦截器</p>
*/
private static class HeadersLoggingInterceper implements ClientHttpRequestInterceptor {

@Override
public ClientHttpResponse intercept(HttpRequest httpRequest, byte[] bytes, ClientHttpRequestExecution clientHttpRequestExecution) throws IOException {
log.info(String.format("请求地址: %s", httpRequest.getURI()));
log.info(String.format("请求头信息: %s", httpRequest.getHeaders()));
ClientHttpResponse response = clientHttpRequestExecution.execute(httpRequest, bytes);
log.info(String.format("响应头信息: %s", response.getHeaders()));
return response;
}
}


}

WebClientUtil

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
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
package org.example;

import io.netty.channel.ChannelOption;
import io.netty.handler.timeout.ReadTimeoutHandler;
import io.netty.handler.timeout.WriteTimeoutHandler;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.io.FileSystemResource;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.client.reactive.ClientHttpConnector;
import org.springframework.http.client.reactive.ReactorClientHttpConnector;
import org.springframework.http.client.reactive.ReactorResourceFactory;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.reactive.function.client.ClientResponse;
import org.springframework.web.reactive.function.client.WebClient;
import reactor.core.publisher.Mono;
import reactor.netty.http.client.HttpClient;
import reactor.netty.resources.ConnectionProvider;
import reactor.netty.resources.LoopResources;

import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;

/**
* <p></p>
* Created by hanqf on 2020/4/23 21:33.
*/

@Slf4j
public class WebClientUtil {

private static final ReactorResourceFactory factory = new ReactorResourceFactory();

private static final WebClient webClient;

static {
factory.setUseGlobalResources(false);
factory.setConnectionProvider(ConnectionProvider.create("httpClient", 50));
factory.setLoopResources(LoopResources.create("httpClient", 50, true));

Function<HttpClient, HttpClient> mapper = client ->
client.tcpConfiguration(c ->
c.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 5000)
.option(ChannelOption.TCP_NODELAY, true)
.doOnConnected(conn -> {
conn.addHandlerLast(new ReadTimeoutHandler(10));
conn.addHandlerLast(new WriteTimeoutHandler(10));
}));

ClientHttpConnector connector =
new ReactorClientHttpConnector(factory, mapper);

webClient = WebClient.builder()
.filter((request, next) -> { //过滤器,3次重试,header打印
log.info(String.format("请求地址: %s", request.url()));
log.info(String.format("请求头信息: %s", request.headers()));
Mono<ClientResponse> exchange = next.exchange(request).retry(3);
ClientResponse clientResponse = exchange.block();
log.info(String.format("响应头信息: %s", clientResponse.headers().asHttpHeaders()));
return exchange;
})
.clientConnector(connector).build();

}


public static String get(String url) {
return get(url, new HashMap<>());
}

/**
* <p>get请求</p>
*
* @param url
* @param map
* @return java.lang.String
* @author hanqf
* 2020/4/24 14:44
*/
public static String get(String url, Map<String, Object> map) {
if (map.size() > 0) {
StringBuilder stringBuffer = new StringBuilder();
stringBuffer.append(url);
if (url.contains("?")) {
stringBuffer.append("&");
} else {
stringBuffer.append("?");
}
for (String key : map.keySet()) {
stringBuffer.append(key).append("=").append(map.get(key).toString()).append("&");
}
url = stringBuffer.toString();
}
String responseResult = null;
Mono<String> mono = webClient.get().uri(url).retrieve().bodyToMono(String.class);
responseResult = mono.block();

return responseResult;
}

public static byte[] getBytes(String url, Map<String, Object> map) {
if (map.size() > 0) {
StringBuilder stringBuffer = new StringBuilder();
stringBuffer.append(url);
if (url.contains("?")) {
stringBuffer.append("&");
} else {
stringBuffer.append("?");
}
for (String key : map.keySet()) {
stringBuffer.append(key).append("=").append(map.get(key).toString()).append("&");
}
url = stringBuffer.toString();
}
byte[] bytes = null;
Mono<ClientResponse> exchange = webClient.get().uri(url).exchange();
ClientResponse response = exchange.block();
if (response.statusCode() == HttpStatus.OK) {
Mono<byte[]> mono = response.bodyToMono(byte[].class);
bytes = mono.block();

//判断是否需要解压,即服务器返回是否经过了gzip压缩--start
List<String> header = response.headers().header("Content-Encoding");
if (header.contains("gzip")) {
GZIPInputStream gzipInputStream = null;
ByteArrayOutputStream out = null;
try {
gzipInputStream = new GZIPInputStream(new ByteArrayInputStream(bytes));
out = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int offset = -1;
while ((offset = gzipInputStream.read(buffer)) != -1) {
out.write(buffer, 0, offset);
}
bytes = out.toByteArray();

} catch (IOException e) {
e.printStackTrace();
} finally {
try {
gzipInputStream.close();
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
//判断是否需要解压,即服务器返回是否经过了gzip压缩--end
}

return bytes;
}

public static String post(String url) {
return post(url, new HashMap<>());
}

/**
* <p>post请求</p>
*
* @param url
* @param params
* @return java.lang.String
* @author hanqf
* 2020/4/24 14:43
*/
public static String post(String url, Map<String, Object> params) {
MultiValueMap<String, Object> map = new LinkedMultiValueMap<>();
if (params != null && params.size() > 0) {
map.setAll(params);
}
String responseResult = null;
Mono<String> mono = webClient.post().uri(url).bodyValue(map).retrieve().bodyToMono(String.class);
responseResult = mono.block();

return responseResult;
}

public static byte[] postBytes(String url, Map<String, Object> params) {
MultiValueMap<String, Object> map = new LinkedMultiValueMap<>();
if (params != null && params.size() > 0) {
map.setAll(params);
}
byte[] bytes = null;
Mono<ClientResponse> exchange = webClient.post().uri(url).bodyValue(map).exchange();
ClientResponse response = exchange.block();
if (response.statusCode() == HttpStatus.OK) {
Mono<byte[]> mono = response.bodyToMono(byte[].class);
bytes = mono.block();

//判断是否需要解压,即服务器返回是否经过了gzip压缩--start
List<String> header = response.headers().header("Content-Encoding");
if (header.contains("gzip")) {
GZIPInputStream gzipInputStream = null;
ByteArrayOutputStream out = null;
try {
gzipInputStream = new GZIPInputStream(new ByteArrayInputStream(bytes));
out = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int offset;
while ((offset = gzipInputStream.read(buffer)) != -1) {
out.write(buffer, 0, offset);
}
bytes = out.toByteArray();

} catch (IOException e) {
e.printStackTrace();
} finally {
try {
gzipInputStream.close();
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
//判断是否需要解压,即服务器返回是否经过了gzip压缩--end
}


return bytes;
}

/**
* <p>post请求,form表单提交</p>
*
* @param url
* @param params 这里要注意将参数值转为字符串,否则会报类型错误
* @return java.lang.String
* @author hanqf
* 2020/4/24 14:43
*/
public static String postForm(String url, Map<String, Object> params) {
MultiValueMap<String, Object> map = new LinkedMultiValueMap<>();
if (params != null && params.size() > 0) {
for (String key : params.keySet()) {
map.add(key, params.get(key).toString());
}
}
String responseResult;
Mono<String> mono = webClient.post().uri(url).contentType(MediaType.APPLICATION_FORM_URLENCODED).bodyValue(map).retrieve().bodyToMono(String.class);
responseResult = mono.block();

return responseResult;
}


public static String postJson(String url, String json) {
return postJson(url, json, false);
}

/**
* <p>post请求,json</p>
*
* @param url
* @param json
* @param gzip
* @return java.lang.String
* @author hanqf
* 2020/4/24 15:45
*/
public static String postJson(String url, String json, boolean gzip) {
String responseResult;
if (gzip) {
byte[] bytes = json.getBytes(StandardCharsets.UTF_8);
return postBytes(url, bytes, true);
} else {
Mono<String> mono = webClient.post().uri(url).contentType(MediaType.APPLICATION_JSON).bodyValue(json).retrieve().bodyToMono(String.class);
responseResult = mono.block();
}

return responseResult;
}

public static String postBytes(String url, byte[] bytes) {
return postBytes(url, bytes, false);
}

/**
* <p>post请求,字节流</p>
*
* @param url
* @param bytes
* @param gzip
* @return java.lang.String
* @author hanqf
* 2020/4/24 15:45
*/
public static String postBytes(String url, byte[] bytes, boolean gzip) {
String responseResult;
Mono<String> mono = null;
WebClient.RequestBodySpec requestBodySpec = webClient.post().uri(url).contentType(MediaType.APPLICATION_OCTET_STREAM);
if (gzip) {
try {
//headers.add("Content-Encoding", "gzip");
ByteArrayOutputStream originalContent = new ByteArrayOutputStream();
originalContent.write(bytes);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
GZIPOutputStream gzipOut = new GZIPOutputStream(baos);
originalContent.writeTo(gzipOut);
gzipOut.finish();
bytes = baos.toByteArray();
mono = requestBodySpec.header("Content-Encoding", "gzip").bodyValue(bytes).retrieve().bodyToMono(String.class);
} catch (Exception e) {
e.printStackTrace();
}
} else {
mono = requestBodySpec.bodyValue(bytes).retrieve().bodyToMono(String.class);
}
responseResult = mono.block();

return responseResult;

}


public static String postStream(String url, InputStream is) {
return postStream(url, is, false);
}

/**
* <p>post请求,流</p>
*
* @param url
* @param is
* @param gzip
* @return java.lang.String
* @author hanqf
* 2020/4/22 17:12
*/
public static String postStream(String url, InputStream is, boolean gzip) {
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int ch;
byte[] bytes = null;
try {
while ((ch = is.read(buffer)) != -1) {
byteArrayOutputStream.write(buffer, 0, ch);
}
bytes = byteArrayOutputStream.toByteArray();
byteArrayOutputStream.close();
} catch (Exception e) {
e.printStackTrace();
}

return postBytes(url, bytes, gzip);

}


public static String postFiles(String url, File[] files) {
return postFiles(url, new HashMap<>(), files);
}

/**
* <p>post请求,文件</p>
*
* @param url
* @param params
* @param files
* @return java.lang.String
* @author hanqf
* 2020/4/24 15:46
*/
public static String postFiles(String url, Map<String, Object> params, File[] files) {
String responseResult;
MultiValueMap<String, Object> map = new LinkedMultiValueMap<>();
if (params != null && params.size() > 0) {
map.setAll(params);
}

for (File file : files) {
map.add("files", new FileSystemResource(file));
}
Mono<String> mono = webClient.post().uri(url).contentType(MediaType.MULTIPART_FORM_DATA).bodyValue(map).retrieve().bodyToMono(String.class);
responseResult = mono.block();

return responseResult;

}

}