package connect.http.sink;
import java.io.IOException;
import java.io.InterruptedIOException;
import java.io.UnsupportedEncodingException;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import javax.net.ssl.SSLException;
import javax.net.ssl.SSLHandshakeException;
import org.apache.http.HttpEntity;
import org.apache.http.HttpEntityEnclosingRequest;
import org.apache.http.HttpHost;
import org.apache.http.HttpRequest;
import org.apache.http.NameValuePair;
import org.apache.http.NoHttpResponseException;
import org.apache.http.client.HttpRequestRetryHandler;
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.protocol.HttpClientContext;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.ConnectTimeoutException;
import org.apache.http.conn.routing.HttpRoute;
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.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.message.BasicNameValuePair;
import org.apache.http.protocol.HttpContext;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class HttpClientPool {
public static final Logger log = LoggerFactory.getLogger(HttpClientPool.class);
static final int timeOut = 10 * 1000;
private static CloseableHttpClient httpClient = null;
//support thread pool invoke http client
private final static Object syncLock = new Object();
private static void config(HttpRequestBase httpRequestBase) {
//set Header
//set request timeout
RequestConfig requestConfig = RequestConfig.custom()
.setConnectionRequestTimeout(timeOut)
.setConnectTimeout(timeOut).setSocketTimeout(timeOut).build();
httpRequestBase.setConfig(requestConfig);
}
public static CloseableHttpClient getHttpClient(String url) {
String hostname = url.split("/")[2];
int port = 80;
if (hostname.contains(":")) {
String[] arr = hostname.split(":");
hostname = arr[0];
port = Integer.parseInt(arr[1]);
}
if (httpClient == null) {
synchronized (syncLock) {
if (httpClient == null) {
httpClient = createHttpClient(100, 40, 100, hostname, port);
}
}
}
return httpClient;
}
public static CloseableHttpClient createHttpClient(int maxTotal,
int maxPerRoute, int maxRoute, String hostname, int port) {
ConnectionSocketFactory plainsf = PlainConnectionSocketFactory
.getSocketFactory();
LayeredConnectionSocketFactory sslsf = SSLConnectionSocketFactory
.getSocketFactory();
//support http and https connect
Registry<ConnectionSocketFactory> registry = RegistryBuilder
.<ConnectionSocketFactory> create().register("http", plainsf)
.register("https", sslsf).build();
PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager(
registry);
// set max connect,we set default is 100
cm.setMaxTotal(maxTotal);
// route means destination server url,we set default is 20
cm.setDefaultMaxPerRoute(maxPerRoute);
HttpHost httpHost = new HttpHost(hostname, port);
// set destination server's route more large,we set default is 40
cm.setMaxPerRoute(new HttpRoute(httpHost), maxRoute);
// request retry
HttpRequestRetryHandler httpRequestRetryHandler = new HttpRequestRetryHandler() {
public boolean retryRequest(IOException exception,
int executionCount, HttpContext context) {
if (executionCount >= 5) {
log.error("Create http connect retry great than 5 times.");
return false;
}
if (exception instanceof NoHttpResponseException) {
log.warn(exception.getMessage()+", Http Server drop our connection, just retry...");
return true;
}
if (exception instanceof SSLHandshakeException) {//if met ssl error
log.error(exception.getMessage()+", The server need SSL...");
return false;
}
if (exception instanceof InterruptedIOException) {//if timeout
log.error(exception.getMessage()+", Retry time out");
return false;
}
if (exception instanceof UnknownHostException) {//if can't connect to unknown server
log.error(exception.getMessage());
return false;
}
if (exception instanceof ConnectTimeoutException) {//if connect timeout
log.error(exception.getMessage());
return false;
}
if (exception instanceof SSLException) {// SSL exception
log.error(exception.getMessage());
return false;
}
HttpClientContext clientContext = HttpClientContext.adapt(context);
HttpRequest request = clientContext.getRequest();
if (!(request instanceof HttpEntityEnclosingRequest)) {
return true;
}
return false;
}
};
CloseableHttpClient httpClient = HttpClients.custom()
.setConnectionManager(cm)//crete connection manager for closeable use.
.setRetryHandler(httpRequestRetryHandler).build();
return httpClient;
}
private static void setPostParams(HttpPost httpPost,
Map<String, Object> params) {
List<NameValuePair> nvps = new ArrayList<NameValuePair>();
Set<String> keySet = params.keySet();
for (String key : keySet) {
nvps.add(new BasicNameValuePair(key, params.get(key).toString()));
}
try {
httpPost.setEntity(new UrlEncodedFormEntity(nvps, "UTF-8"));
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
private static void setPostParams(HttpPost httpPost,
String json) {
StringEntity stringEntity = new StringEntity(json, "UTF-8");
stringEntity.setContentEncoding("UTF-8");
//set special header
httpPost.setEntity(stringEntity);
}
public static String post(String url, Map<String, Object> params) throws IOException {
HttpPost httppost = new HttpPost(url);
config(httppost);
setPostParams(httppost, params);
CloseableHttpResponse response = null;
try {
response = getHttpClient(url).execute(httppost,
HttpClientContext.create());
HttpEntity entity = response.getEntity();
String result = EntityUtils.toString(entity, "utf-8");
EntityUtils.consume(entity);
return result;
} catch (Exception e) {
e.printStackTrace();
log.error(e.getMessage());
throw e;
} finally {
try {
if (response != null)
response.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public static boolean post(String url, String params) {
HttpPost httppost = new HttpPost(url);
config(httppost);
setPostParams(httppost, params);
CloseableHttpResponse response = null;
try {
response = getHttpClient(url).execute(httppost,
HttpClientContext.create());
HttpEntity entity = response.getEntity();
String result = EntityUtils.toString(entity, "utf-8");
int responseCode = response.getStatusLine().getStatusCode();
EntityUtils.consume(entity);
if(responseCode == 200) {
log.info("Success post, response result="+result);
return true;
}else {
log.error("Fail to post to {}, body={},responseCode={}",url,params,responseCode);
return false;
}
} catch (Exception e) {
e.printStackTrace();
log.error("Fail to post to {}, body={}",url,params);
log.error(e.getMessage());
return false;
} finally {
try {
if (response != null)
response.close();
} catch (IOException e) {
log.error(e.getMessage());
e.printStackTrace();
}
}
}
public static String get(String url) {
HttpGet httpget = new HttpGet(url);
config(httpget);
CloseableHttpResponse response = null;
try {
response = getHttpClient(url).execute(httpget,
HttpClientContext.create());
HttpEntity entity = response.getEntity();
String result = EntityUtils.toString(entity, "utf-8");
EntityUtils.consume(entity);
return result;
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (response != null)
response.close();
} catch (IOException e) {
log.error(e.getMessage());
e.printStackTrace();
}
}
return null;
}
public static void main(String[] args) {
// URL列表数组
String[] urisToGet = {
};
long start = System.currentTimeMillis();
try {
int pagecount = urisToGet.length;
ExecutorService executors = Executors.newFixedThreadPool(pagecount);
CountDownLatch countDownLatch = new CountDownLatch(pagecount);
for (int i = 0; i < pagecount; i++) {
HttpGet httpget = new HttpGet(urisToGet[i]);
config(httpget);
// 启动线程抓取
executors.execute(new GetRunnable(urisToGet[i], countDownLatch));
}
countDownLatch.await();
executors.shutdown();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
System.out.println("线程" + Thread.currentThread().getName() + ","
+ System.currentTimeMillis() + ", 所有线程已完成,开始进入下一步!");
}
long end = System.currentTimeMillis();
System.out.println("consume -> " + (end - start));
}
static class GetRunnable implements Runnable {
private CountDownLatch countDownLatch;
private String url;
public GetRunnable(String url, CountDownLatch countDownLatch) {
this.url = url;
this.countDownLatch = countDownLatch;
}
@Override
public void run() {
try {
System.out.println(HttpClientPool.get(url));
} finally {
countDownLatch.countDown();
}
}
}
}