Java 第三方包-HttpClient

1. wiki

2. 引入

1
2
3
4
5
6
<!-- https://mvnrepository.com/artifact/org.apache.httpcomponents/httpclient -->
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.13</version>
</dependency>

3. 使用

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
private static final int MAX_CONNECTION             = 10;
private static final int DEFAULT_MAX_CONNECTION = 5;
private static final int CONNECT_TIMEOUT = 2000; // ms毫秒,建立链接超时时间
private static final int SOCKET_TIMEOUT = 2000; // ms毫秒,读取超时时间
private static final int CONNECTION_REQUEST_TIMEOUT = 500; // ms毫秒,从池中获取链接超时时间
// 连接管理器,使用无惨构造
private static PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager();
private static HttpClientBuilder httpBuilder = null;

static{
/******************** 连接数相关设置(默认配置和某个host的配置) ********************/
// 最大连接数
connManager.setMaxTotal(200);
// 默认的每个路由的最大连接数
connManager.setDefaultMaxPerRoute(100);
// 设置到某个路由的最大连接数,会覆盖defaultMaxPerRoute
connManager.setMaxPerRoute(new HttpRoute(new HttpHost("somehost", 80)), 150);//针对具体的某个路由的特殊设置

/******************** socket配置(默认配置和某个host的配置) ********************/
SocketConfig socketConfig = SocketConfig.custom()
.setTcpNoDelay(true) // 是否立即发送数据,设置为true会关闭Socket缓冲,默认为false
.setSoReuseAddress(true) // 是否可以在一个进程关闭Socket后,即使它还没有释放端口,其它进程还可以立即重用端口
.setSoTimeout(500) // 接收数据的等待超时时间,单位ms
.setSoLinger(60) // 关闭Socket时,要么发送完所有数据,要么等待60s后,就关闭连接,此时socket.close()是阻塞的
.setSoKeepAlive(true) // 开启监视TCP连接是否有效
.build();
connManager.setDefaultSocketConfig(socketConfig);
connManager.setSocketConfig(new HttpHost("somehost", 80), socketConfig);//针对具体的某个路由的特殊设置

/******************** HTTP connection相关配置(默认配置和某个host的配置),一般不修改 ********************/
// 消息约束
MessageConstraints messageConstraints = MessageConstraints.custom()
.setMaxHeaderCount(200)
.setMaxLineLength(2000)
.build();
// Http connection相关配置
ConnectionConfig connectionConfig = ConnectionConfig.custom()
.setMalformedInputAction(CodingErrorAction.IGNORE)
.setUnmappableInputAction(CodingErrorAction.IGNORE)
.setCharset(Consts.UTF_8)
.setMessageConstraints(messageConstraints)
.build();
// 一般不修改HTTP connection相关配置,故不设置
// connManager.setDefaultConnectionConfig(connectionConfig);
// connManager.setConnectionConfig(new HttpHost("somehost", 80), ConnectionConfig.DEFAULT);

/******************** 重试处理 默认是重试3次 ********************/
// 禁用重试(参数:retryCount、requestSentRetryEnabled)
HttpRequestRetryHandler requestRetryHandler = new DefaultHttpRequestRetryHandler(0, false);
// 自定义重试策略
HttpRequestRetryHandler myRetryHandler = new HttpRequestRetryHandler() {

public boolean retryRequest(IOException exception, int executionCount, HttpContext context) {
// Do not retry if over max retry count
if (executionCount >= 3) {
return false;
}
// Timeout
if (exception instanceof InterruptedIOException) {
return false;
}
// Unknown host
if (exception instanceof UnknownHostException) {
return false;
}
// Connection refused
if (exception instanceof ConnectTimeoutException) {
return false;
}
// SSL handshake exception
if (exception instanceof SSLException) {
return false;
}

HttpClientContext clientContext = HttpClientContext.adapt(context);
HttpRequest request = clientContext.getRequest();
boolean idempotent = !(request instanceof HttpEntityEnclosingRequest);
// Retry if the request is considered idempotent
// 如果请求类型不是 HttpEntityEnclosingRequest,被认为是幂等的,那么就重试
// HttpEntityEnclosingRequest 指的是有请求体的 request,比 HttpRequest 多一个 Entity 属性
// 而常用的 GET 请求是没有请求体的,POST、PUT 都是有请求体的
// Rest一般用 GET 请求获取数据,故幂等,POST 用于新增数据,故不幂等
if (idempotent) {
return true;
}

return false;
}
};

/******************** request 请求相关配置 ********************/
RequestConfig defaultRequestConfig = RequestConfig .custom()
.setConnectTimeout(CONNECT_TIMEOUT) // 连接超时:指的是连接一个url的连接等待时间
.setSocketTimeout(SOCKET_TIMEOUT) // 读取数据超时:指的是连接上一个url,获取response的返回等待时间
.setConnectionRequestTimeout(CONNECTION_REQUEST_TIMEOUT) // 从连接池获取连接的超时时间
.setStaleConnectionCheckEnabled(true) // 检查是否为陈旧的连接,默认为true,类似testOnBorrow
.build();

httpBuilder = HttpClients.custom();
httpBuilder.setConnectionManager(connectionManager);
}

public static CloseableHttpClient getConnection() {
CloseableHttpClient httpClient = httpBuilder.build();
return httpClient;
}