HttpClient简单理解和使用
HttpClient的简介
- 当有连接第一次使用的时候建立连接
- 结束连接不关闭,归还到池中
- 下次同个目的连接可以从池中直接获取
- 定时清理过期连接
- 定义需要的属性
- 与http协议对接
使用场景
一是爬虫 ,但是我们不是面向监狱编程,我们是面向对象,所以大多是时候我们选择的是第二种,通过构建HttpClient连接池使用第三方的api。
依赖
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.2</version>
</dependency>
代码
/**
* 自己编写一个连接池的工具类
*/
public class HttpClientUtil {
/**
* 日志文件
*/
private static final Logger log = LoggerFactory.getLogger(HttpClientUtil.class);
/**
* http链接池
*/
private static PoolingHttpClientConnectionManager cm = null;
/**
* http客户端
*/
private static CloseableHttpClient httpClient = null;
/**
* from-请求/响应 类型
*/
public static final String CONTENT_TYPE_FORM = "application/x-www-form-urlencoded;charset=UTF-8";
/**
* json-请求/响应 类型
*/
public static final String CONTENT_TYPE_JSON = "application/json;charset=UTF-8";
/**
* 长连接时间保持设置
*/
private static final int HTTP_DEFAULT_KEEP_TIME = 60000;
/**
* 1、MaxtTotal是整个池子的大小;
* 2、.实际大小是该属性,该路由只能由1000的连接,既可以不考虑MaxTotal
*/
private static final int DEFAULT_MAX_PER_ROUTE = 1000;
/**
* 设置连接池的大小
*/
private static final int MAX_TOTAL = 1000;
/**
* 设置链接超时
*/
private static final int CONNECTION_TIMEOUT = 60000;
/**
* 设置等待数据超时时间
*/
private static final int SOCKET_TIMEOUT = 60000;
/**
* 初始化连接池
*/
private static synchronized void initPools() {
//如果客戶端为空在连接池中创建一个客户端,我个人理解为连接
if (httpClient == null) {
cm = new PoolingHttpClientConnectionManager();
cm.setDefaultMaxPerRoute(DEFAULT_MAX_PER_ROUTE);
cm.setMaxTotal(MAX_TOTAL);
httpClient = HttpClients.custom().setKeepAliveStrategy(defaultStrategy).setConnectionManager(cm).build();
}
}
/**
* 长连接保持设置 Http connection keepAlive 设置,可以用来解决连接失效的长连接问题,先认为是默认策略
*/
private static ConnectionKeepAliveStrategy defaultStrategy = new ConnectionKeepAliveStrategy() {
@Override
public long getKeepAliveDuration(HttpResponse response, HttpContext context) {
HeaderElementIterator it = new BasicHeaderElementIterator(response.headerIterator(HTTP.CONN_KEEP_ALIVE));
int keepTime = HTTP_DEFAULT_KEEP_TIME;
while (it.hasNext()) {
HeaderElement he = it.nextElement();
String param = he.getName();
String value = he.getValue();
if (value != null &&"timeout".equalsIgnoreCase(param)) {
try {
return Long.parseLong(value) * 1000;
} catch (Exception e) {
log.error("format KeepAlive timeout exception, exception:{}", e.toString());
throw e;
}
}
}
return keepTime * 1000;
}
};
/**
* 执行http post 请求 默认采用Content-Type:application/json 响应
* 默认采用Content-Type:application/json
*
* @param uri 请求地址
* @param data 请求数据
* @return String 返回是数据
* @throws Exception 请求异常
*/
public static String sendPost(String uri, String data) throws Exception {
return sendPost(uri, data, CONTENT_TYPE_JSON, CONTENT_TYPE_JSON, null);
}
/**
*
* @param uri
* @param param
* @return
* @throws Exception
*/
public static String sendPost(String uri, Map<String, String> param) throws Exception {
return sendPost(uri, param, CONTENT_TYPE_FORM, CONTENT_TYPE_FORM, null);
}
private static String sendPost(String uri, Map<String, String> param, String reqContentType, String respContentType,
Map<String, String> headers) throws Exception {
long startTime = System.currentTimeMillis();
HttpEntity httpEntity = null;
HttpEntityEnclosingRequestBase method = null;
String responseBody = "";
try {
if (httpClient == null) {
initPools();
}
method = (HttpEntityEnclosingRequestBase) getRequest(uri, HttpPost.METHOD_NAME, reqContentType,
respContentType);
if (param != null && param.size() > 0) {
//UrlEncodedFormEntity 的构造器只接受 List<? extends BasicNameValuePair> 等作为参数,不接受 Map所以需要做一个转换
List<BasicNameValuePair> params = new ArrayList<BasicNameValuePair>(param.size());
Iterator<Entry<String, String>> iterator = param.entrySet().iterator();
while (iterator.hasNext()) {
Entry<String, String> entry = iterator.next();
params.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));
}
method.setEntity(new UrlEncodedFormEntity(params, "UTF-8"));
}
if (headers != null && headers.size() > 0) {
Iterator<Entry<String, String>> iterator = headers.entrySet().iterator();
while (iterator.hasNext()) {
Entry<String, String> entry = iterator.next();
method.addHeader(entry.getKey(), entry.getValue());
}
}
HttpContext context = HttpClientContext.create();
CloseableHttpResponse httpResponse = httpClient.execute(method, context);
httpEntity = httpResponse.getEntity();
if (httpEntity != null) {
responseBody = EntityUtils.toString(httpEntity, "UTF-8");
}
} catch (Exception e) {
if (method != null) {
method.abort();
}
log.error("execute post request exception, url:{},exception:{}, cost time(ms):{}", uri, e.toString(),
System.currentTimeMillis() - startTime);
throw e;
} finally {
if (httpEntity != null) {
try {
EntityUtils.consumeQuietly(httpEntity);
} catch (Exception e) {
e.printStackTrace();
log.error("execute post request exception, url:{},exception:{}, cost time(ms):{}", uri,
e.toString(), System.currentTimeMillis() - startTime);
throw e;
}
}
}
return responseBody;
}
/**
* 执行http post 请求 默认采用Content-Type:application/json 响应
* 默认采用Content-Type:application/json
*
* @param uri 请求地址
* @param data 请求数据
* @return String 返回是数据
* @throws Exception 请求异常
*/
public static String sendPost(String uri, String data, Map<String, String> headers) throws Exception {
return sendPost(uri, data, CONTENT_TYPE_JSON, CONTENT_TYPE_JSON, headers);
}
/**
* 执行http post请求
*
* @param uri 请求地址
* @param data 请求数据
* @param reqContentType 请求content-type
* @param respContentType 响应content-type
* @return String 返回请求结果
* @throws Exception 异常
*/
public static String sendPost(String uri, String data, String reqContentType, String respContentType,
Map<String, String> headers) throws Exception {
long startTime = System.currentTimeMillis();
HttpEntity httpEntity = null;
HttpEntityEnclosingRequestBase method = null;
String responseBody = "";
try {
if (httpClient == null) {
initPools();
}
//获取地址判断方法,结束响应格式等等
method = (HttpEntityEnclosingRequestBase) getRequest(uri, HttpPost.METHOD_NAME, reqContentType,
respContentType);
method.setEntity(new StringEntity(data, Charset.forName("UTF-8")));
//如果请求头有参数将请求头的参数进行添加
if (headers != null && headers.size() > 0) {
Iterator<Entry<String, String>> iterator = headers.entrySet().iterator();
while (iterator.hasNext()) {
Entry<String, String> entry = iterator.next();
method.addHeader(entry.getKey(), entry.getValue());
}
}
//固定写法,获取一些http的特定属性
HttpContext context = HttpClientContext.create();
//执行请求
CloseableHttpResponse httpResponse = httpClient.execute(method, context);
httpEntity = httpResponse.getEntity();
if (httpEntity != null) {
responseBody = EntityUtils.toString(httpEntity, "UTF-8");
log.debug("post请求信息:\n请求URL: {},\n请求参数{},\n返回状态码:{},\n返回结果:{}", uri, data,
httpResponse.getStatusLine().getStatusCode(), responseBody);
}
} catch (Exception e) {
if (method != null) {
method.abort();
}
log.error("execute post request exception, url:{},exception:{}, cost time(ms):{}", uri, e.toString(),
System.currentTimeMillis() - startTime);
throw e;
} finally {
if (httpEntity != null) {
try {
//关闭流
EntityUtils.consumeQuietly(httpEntity);
} catch (Exception e) {
e.printStackTrace();
log.error("execute post request exception, url:{},exception:{}, cost time(ms):{}", uri,
e.toString(), System.currentTimeMillis() - startTime);
throw e;
}
}
}
return responseBody;
}
/**
* 执行GET 请求 请求 默认采用Content-Type:application/json 响应
* 默认采用Content-Type:application/json
*
* @param uri 请求链接
* @return String 请求结果
* @throws Exception 异常
*/
public static String sendGet(String uri,Map<String, String> headers) throws Exception {
return sendGet(uri, CONTENT_TYPE_JSON, CONTENT_TYPE_JSON,headers);
}
/**
* 执行GET 请求
*
* @param uri 请求链接
* @param reqContentType 请求ContentType
* @param respContentType 响应ContentType
* @return String 响应数据
* @throws Exception 异常
*/
public static String sendGet(String uri, String reqContentType, String respContentType,Map<String, String> headers) throws Exception {
long startTime = System.currentTimeMillis();
HttpEntity httpEntity = null;
HttpRequestBase method = null;
String responseBody = "";
try {
if (httpClient == null) {
initPools();
}
method = getRequest(uri, HttpGet.METHOD_NAME, reqContentType, respContentType);
HttpContext context = HttpClientContext.create();
if (headers != null && headers.size() > 0) {
//使用迭代器获取请求头信息
Iterator<Entry<String, String>> iterator = headers.entrySet().iterator();
while (iterator.hasNext()) {
Entry<String, String> entry = iterator.next();
method.addHeader(entry.getKey(), entry.getValue());
}
}
CloseableHttpResponse httpResponse = httpClient.execute(method, context);
httpEntity = httpResponse.getEntity();
if (httpEntity != null) {
responseBody = EntityUtils.toString(httpEntity, "UTF-8");
log.debug("get请求信息:\n请求URL: {},\n返回状态码:{},\n返回结果:{}", uri, httpResponse.getStatusLine().getStatusCode(),
responseBody);
}
} catch (Exception e) {
if (method != null) {
method.abort();
}
log.error("execute get request exception, url:{},exception:{}, cost time(ms):{}", uri, e.toString(),
System.currentTimeMillis() - startTime);
throw e;
} finally {
if (httpEntity != null) {
try {
EntityUtils.consumeQuietly(httpEntity);
} catch (Exception e) {
log.error("execute get request exception, url:{},exception:{}, cost time(ms):{}", uri, e.toString(),
System.currentTimeMillis() - startTime);
throw e;
}
}
}
return responseBody;
}
/**
* 创建请求
*
* @param uri 请求url
* @param methodName 请求的方法类型
* @param reqContentType 请求ContentType
* @param respContentType 响应ContentType
* @return HttpRequestBase http请求的基本实现对象
*/
private static HttpRequestBase getRequest(String uri, String methodName, String reqContentType,
String respContentType) {
HttpRequestBase method = null;
//超时时间,等待时间配置,连接时间分配置
RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(SOCKET_TIMEOUT)
.setConnectTimeout(CONNECTION_TIMEOUT).setConnectionRequestTimeout(CONNECTION_TIMEOUT)
.setExpectContinueEnabled(false).build();
if (HttpPut.METHOD_NAME.equalsIgnoreCase(methodName)) {
method = new HttpPut(uri);
} else if (HttpPost.METHOD_NAME.equalsIgnoreCase(methodName)) {
method = new HttpPost(uri);
} else if (HttpGet.METHOD_NAME.equalsIgnoreCase(methodName)) {
method = new HttpGet(uri);
} else {
method = new HttpPost(uri);
}
if (StringUtils.isBlank(reqContentType)) {
reqContentType = CONTENT_TYPE_FORM;
}
// 请求类型
method.addHeader("Content-Type", reqContentType);
method.addHeader("Accept", respContentType);
//添加配置
method.setConfig(requestConfig);
return method;
}
/**
* 获取 httpClient客户端
*
* @return CloseableHttpClient
*/
public static CloseableHttpClient getHttpClient() {
return httpClient;
}
/**
* 获取 httpClient连接池
*
* @return PoolingHttpClientConnectionManager
*/
public static PoolingHttpClientConnectionManager getHttpConnectionManager() {
return cm;
}
}