package com.github.qcloudsms.httpclient;
import org.apache.http.Header;
import org.apache.http.entity.ByteArrayEntity;
import org.apache.http.util.EntityUtils;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.RequestBuilder;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.DefaultConnectionKeepAliveStrategy;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import java.io.IOException;
import java.net.URISyntaxException;
import java.util.Map;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.TimeUnit;
public class PoolingHTTPClient implements HTTPClient {
private PoolingHttpClientConnectionManager connMgr;
private CloseableHttpClient client;
public PoolingHTTPClient(int maxConnection) {
// 生成默认请求配置
RequestConfig.Builder requestConfigBuilder = RequestConfig.custom();
// 超时时间
requestConfigBuilder.setSocketTimeout(5 * 1000);
// 连接时间
requestConfigBuilder.setConnectTimeout(5 * 1000);
RequestConfig defaultRequestConfig = requestConfigBuilder.build();
// 连接池配置
// 长连接保持30秒
this.connMgr=new PoolingHttpClientConnectionManager(30, TimeUnit.MILLISECONDS);
//this.connMgr = new PoolingHttpClientConnectionManager();
// 总连接数
connMgr.setMaxTotal(maxConnection);
// 同路由的并发数
connMgr.setDefaultMaxPerRoute(100);
// httpclient 配置
HttpClientBuilder httpClientBuilder = HttpClientBuilder.create();
// 保持长连接配置,需要在头添加Keep-Alive
httpClientBuilder.setKeepAliveStrategy(new DefaultConnectionKeepAliveStrategy());
httpClientBuilder.setConnectionManager(connMgr);
httpClientBuilder.setDefaultRequestConfig(defaultRequestConfig);
this.client = httpClientBuilder.build();
// 启动定时器,定时回收过期的连接
Timer timer = new Timer();
timer.schedule(new TimerTask() {
@Override
public void run() {
System.out.println("=====closeIdleConnections===");
connMgr.closeExpiredConnections();
connMgr.closeIdleConnections(5, TimeUnit.SECONDS);
}
}, 10 * 1000, 5 * 1000);
System.out.println("===== Apache httpclient 初始化连接池完毕===");
// this.client = HttpClients.custom()
// .setConnectionManager(this.connMgr)
// .build();
}
public PoolingHTTPClient() {
this(100);
}
public HTTPResponse fetch(HTTPRequest request) throws IOException, URISyntaxException {
// Build URI
URIBuilder uriBuilder = new URIBuilder(request.url);
for (Map.Entry<String, String> entry: request.parameters.entrySet()) {
uriBuilder.addParameter(entry.getKey(), entry.getValue());
}
// Build request
RequestConfig reqConfig = RequestConfig.custom()
.setConnectTimeout(request.connectTimeout)
.setConnectionRequestTimeout(request.requestTimeout)
.build();
RequestBuilder reqBuilder = RequestBuilder.create(request.method.name())
.setUri(uriBuilder.build())
.setEntity(new ByteArrayEntity(request.body.getBytes(request.bodyCharset)))
.setConfig(reqConfig);
for (Map.Entry<String, String> entry: request.headers.entrySet()) {
reqBuilder.setHeader(entry.getKey(), entry.getValue());
}
// Fetch http response
HttpClientContext ctx = HttpClientContext.create();
CloseableHttpResponse response = client.execute(reqBuilder.build(), ctx);
try {
// May throw IOException
HTTPResponse res = new HTTPResponse()
.setRequest(request)
.setStatusCode(response.getStatusLine().getStatusCode())
.setReason(response.getStatusLine().getReasonPhrase())
.setBody(EntityUtils.toString(response.getEntity(), "UTF-8"));
for (Header header: response.getAllHeaders()) {
res.addHeader(header.getName(), header.getValue());
}
return res;
} finally {
response.close();
}
}
public synchronized void close() {
if (client != null) {
try {
client.close();
} catch (IOException e) {
// in case of a problem or the connection was aborted
}
client = null;
}
if (connMgr != null) {
connMgr.close();
connMgr = null;
}
}
public static void main(String[] args) {
new PoolingHTTPClient(200);
}
}