引入maven依赖
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.1.4</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpcore</artifactId>
<version>4.4.12</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpasyncclient</artifactId>
<version>4.4.12</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpcore-nio</artifactId>
<version>4.4.12</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpmime</artifactId>
<version>4.5.9</version>
</dependency>
import com.alibaba.fastjson.TypeReference;
import com.alibaba.fastjson.util.IOUtils;
import com.google.common.base.Joiner;
import com.google.common.base.Stopwatch;
import com.google.common.collect.Maps;
import com.meituan.mtrace.http.HttpAsyncClients;
import com.meituan.mtrace.http.HttpClients;
import com.sankuai.meituan.common.json.JSONUtil;
import com.sankuai.shangou.empower.uwms.common.utils.FastJsonUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.MapUtils;
import org.apache.http.HttpEntity;
import org.apache.http.HttpStatus;
import org.apache.http.NameValuePair;
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.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.HttpClientConnectionManager;
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.conn.PoolingHttpClientConnectionManager;
import org.apache.http.impl.nio.client.CloseableHttpAsyncClient;
import org.apache.http.impl.nio.conn.PoolingNHttpClientConnectionManager;
import org.apache.http.impl.nio.reactor.DefaultConnectingIOReactor;
import org.apache.http.impl.nio.reactor.IOReactorConfig;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.nio.reactor.ConnectingIOReactor;
import org.apache.http.nio.reactor.IOReactorException;
import org.apache.http.protocol.HttpContext;
import org.apache.http.util.EntityUtils;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class HttpClientUtil {
private static final String CHARSET_UTF8 = "UTF-8";
private static final Pattern HTTP_PATTERN = Pattern.compile("^(https?|ftp|file)://[-a-zA-Z0-9+&@#/%?=~_|!:,.;]*[-a-zA-Z0-9+&@#/%=~_|]");
private static volatile CloseableHttpClient httpClient;
private static volatile CloseableHttpAsyncClient httpAsyncClient;
// 默认socket连接超时时间
private static final int DEFAULT_SOCKET_TIMEOUT = 10 * 1000;
// 默认HTTP连接超时时间
private static final int DEFAULT_CONNECT_TIMEOUT = 5 * 1000;
/**
* 默认请求头
*/
private static final Map<String, String> DEFAULT_HEADER = Maps.newHashMap();
static {
// DEFAULT_HEADER.put("Content-Type", "application/json; charset=UTF-8");
}
private HttpClientUtil() {
}
/**
* 启动时初始化httpClient及连接池的连接数
*/
public static CloseableHttpClient getHttpClient() {
if (null == httpClient) {
synchronized (HttpClientUtil.class) {
if (null == httpClient) {
log.info("HttpClientUtil.getHttpClient, 初始化httpClient");
httpClient = HttpClients.custom().setConnectionManager(
buildConnectionManager()).setRetryHandler(buildRetryHandler()).build();
}
}
}
return httpClient;
}
/**
* 启动时初始化httpAsyncClient及连接池的连接数
*/
public static CloseableHttpAsyncClient getHttpAsyncClient() {
if (null == httpAsyncClient) {
synchronized (HttpClientUtil.class) {
if (null == httpAsyncClient) {
httpAsyncClient = HttpAsyncClients.custom()
.setConnectionManager(buildPoolConnectionManager())
.setDefaultRequestConfig(RequestConfig.custom().setSocketTimeout(DEFAULT_SOCKET_TIMEOUT)
.setConnectTimeout(DEFAULT_CONNECT_TIMEOUT).build()).build();
}
}
}
return httpAsyncClient;
}
/**
* 执行post请求获取响应字符串
*
* @param url 请求url
* @param connectTimeOut 连接超时时间
* @param socketTimeOut socket超时时间
* @param params post请求参数
* @return 响应字符串
*/
public static String post(String url, int connectTimeOut, int socketTimeOut, Map<String, Object> params) {
return post(url, connectTimeOut, socketTimeOut, params, DEFAULT_HEADER);
}
public static String post(String url, int connectTimeOut, int socketTimeOut, Map<String, Object> params,
Map<String, String> headers) {
// 构建httppost请求配置、实体、请求头
HttpPost httpPost = new HttpPost(url);
setPostConfig(httpPost, connectTimeOut, socketTimeOut);
setPostEntity(httpPost, params);
setPostHeader(httpPost, headers);
// 发送post请求
CloseableHttpResponse response = null;
String result = "";
Stopwatch stopwatch = Stopwatch.createStarted();
try {
response = getHttpClient().execute(httpPost);
// 返回不为成功时直接返回null
if (response.getStatusLine().getStatusCode() != HttpStatus.SC_OK) {
log.error("HttpClientUtil.post, 发送POST请求获取响应, httpcode:{}, url:{}, connectTimeOut:{}, socketTimeOut:{}, params:{}, headers:{}",
response.getStatusLine().getStatusCode(), url, connectTimeOut, socketTimeOut, params, headers);
return null;
}
HttpEntity entity = response.getEntity();
result = EntityUtils.toString(entity, CHARSET_UTF8);
if (MccConfigUtil.getCanLogHttpRequestResult()) {
try {
log.info("url = {} param = {}, result = {} header = {}", url, JSONUtil.toJSONString(params), result);
} catch (Exception e) {
log.error("url = {}", url, e);
}
}
return result;
} catch (Exception e) {
log.error("HttpClientUtil.post, 执行POST请求失败, url:{}, connectTimeOut:{}, socketTimeOut:{}, params:{}, headers:{}, exception",
url, connectTimeOut, socketTimeOut, params, headers, e);
return null;
} finally {
// 关闭响应
IOUtils.close(response);
log.info("HttpClientUtil.post, 发送POST请求的url:{}, cost={}", url, stopwatch.elapsed(TimeUnit.MILLISECONDS));
}
}
public static String get(String url, int connectTimeOut, int socketTimeOut, Map<String, String> params) {
return getWithHeader(url, connectTimeOut, socketTimeOut, params, null);
}
/**
* 执行get请求获取响应字符串
*
* @param url 请求url
* @return 响应字符串
*/
public static String getWithHeader(String url, int connectTimeOut, int socketTimeOut, Map<String, String> params,
Map<String, String> header) {
String result = "";
CloseableHttpResponse response = null;
Stopwatch stopwatch = Stopwatch.createStarted();
try {
HttpGet httpGet = new HttpGet(assembleUrl(url, params));
setGetConfig(httpGet, connectTimeOut, socketTimeOut);
if (header != null) {
for (Map.Entry<String, String> entry : header.entrySet()) {
httpGet.setHeader(entry.getKey(), entry.getValue());
}
}
response = getHttpClient().execute(httpGet);
// 返回不为成功时直接返回null
if (response.getStatusLine().getStatusCode() != HttpStatus.SC_OK) {
log.error("HttpClientUtil.get, 发送GET请求获取响应状态, httpcode={}, url:{}, connectTimeOut:{}, socketTimeOut:{}, params:{}",
response.getStatusLine().getStatusCode(), assembleUrl(url, params), connectTimeOut, socketTimeOut, params);
return null;
}
HttpEntity entity = response.getEntity();
result = EntityUtils.toString(entity, CHARSET_UTF8);
return result;
} catch (Exception e) {
log.error("HttpClientUtil.get, 执行GET请求失败, url:{}, connectTimeOut:{}, socketTimeOut:{}, params:{}, exception={}",
assembleUrl(url, params), connectTimeOut, socketTimeOut, FastJsonUtils.toJSONString(params), e);
return null;
} finally {
// 关闭响应
IOUtils.close(response);
if (MccConfigUtil.getCanLogHttpRequestResult()) {
log.info("HttpClientUtil.get, 发送GET请求的, url:{}, param = {} result = {} cost:{}, ",
url,
FastJsonUtils.toJSONString(params),
result,
stopwatch.elapsed(TimeUnit.MILLISECONDS));
}
}
}
/**
* 拼接GET请求参数
*/
public static String assembleUrl(String url, Map<String, String> params) {
//校验参数
if (MapUtils.isEmpty(params)) {
return url;
}
//校验url的准确性
Matcher matcher = HTTP_PATTERN.matcher(url);
if (!matcher.matches()) {
throw new IllegalArgumentException("illegal argument with url = " + url);
}
StringBuilder resultUrl = new StringBuilder(url);
try {
if (!url.contains("?")) {
resultUrl.append("?");
} else {
if (!"?".endsWith(url)) {
resultUrl.append("&");
}
}
return resultUrl.append(Joiner.on("&").withKeyValueSeparator("=").join(params)).toString();
} catch (Exception e) {
log.error("HttpClientUtil.assembleUrl, 拼接url异常, url:{}, exception={}", url, e);
}
return resultUrl.toString();
}
/**
* 设置post请求超时时间
*
* @param httpPost httppost
* @param connectTimeOut 连接超时时间
* @param socketTimeOut socket读写超时时间
*/
private static void setPostConfig(HttpPost httpPost, int connectTimeOut, int socketTimeOut) {
RequestConfig requestConfig = RequestConfig.custom()
.setConnectionRequestTimeout(connectTimeOut)
.setConnectTimeout(connectTimeOut)
.setSocketTimeout(socketTimeOut).build();
httpPost.setConfig(requestConfig);
}
/**
* 设置get请求超时时间
*
* @param httpGet httpget
* @param connectTimeOut 连接超时时间
* @param socketTimeOut socket读写超时时间
*/
private static void setGetConfig(HttpGet httpGet, int connectTimeOut, int socketTimeOut) {
RequestConfig requestConfig = RequestConfig.custom()
.setConnectionRequestTimeout(connectTimeOut)
.setConnectTimeout(connectTimeOut)
.setSocketTimeout(socketTimeOut).build();
httpGet.setConfig(requestConfig);
}
/**
* 设置post请求实体
*
* @param httpPost httppost
* @param params 实体参数
*/
private static void setPostEntity(HttpPost httpPost, Map<String, Object> params) {
// 将map转化成httppost的实体
List<NameValuePair> nvps = new ArrayList<>();
for (Map.Entry<String, Object> entry : params.entrySet()) {
nvps.add(new BasicNameValuePair(entry.getKey(), String.valueOf(entry.getValue())));
}
try {
httpPost.setEntity(new UrlEncodedFormEntity(nvps, CHARSET_UTF8));
} catch (UnsupportedEncodingException e) {
log.error("HttpClientUtil.setPostEntity, 实体转化成UTF-8格式出错, httpPost:{}, params:{}, exception={}", httpPost, params, e);
}
}
/**
* 设置post请求头
*
* @param httpPost httppost
* @param headers 请求头
*/
private static void setPostHeader(HttpPost httpPost, Map<String, String> headers) {
for (Map.Entry<String, String> entry : headers.entrySet()) {
httpPost.setHeader(entry.getKey(), entry.getValue());
}
}
/**
* 构建http连接管理器
*
* @return 连接管理器
*/
private static HttpClientConnectionManager buildConnectionManager() {
ConnectionSocketFactory plainsf = PlainConnectionSocketFactory.getSocketFactory();
LayeredConnectionSocketFactory sslsf = SSLConnectionSocketFactory.getSocketFactory();
Registry<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory>create()
.register("http", plainsf).register("https", sslsf).build();
PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager(registry);
// 将最大连接数增加
cm.setMaxTotal(MccConfigUtil.getHttpMaxTotal());
// 将每个路由基础的连接增加
cm.setDefaultMaxPerRoute(MccConfigUtil.getHttpMaxPerRoute());
return cm;
}
/**
* 构建http异步连接管理器
*
* @return
*/
private static PoolingNHttpClientConnectionManager buildPoolConnectionManager() {
try {
IOReactorConfig ioReactorConfig = IOReactorConfig.custom().setIoThreadCount(MccConfigUtil.getHttpAsyncIoThreadCount()).build();
ConnectingIOReactor ioReactor = new DefaultConnectingIOReactor(ioReactorConfig);
PoolingNHttpClientConnectionManager cm = new PoolingNHttpClientConnectionManager(ioReactor);
cm.setMaxTotal(MccConfigUtil.getHttpAsyncMaxTotal());
cm.setDefaultMaxPerRoute(MccConfigUtil.getHttpAsyncMaxPerRoute());
return cm;
} catch (IOReactorException e) {
log.error("HttpClientUtil.buildPoolConnectionManager, 构建http异步连接管理器异常, exception={}", e);
}
return null;
}
/**
* 构建重试次数的handler
*
* @return handler
*/
private static HttpRequestRetryHandler buildRetryHandler() {
return (IOException exception, int executionCount, HttpContext context) -> {
// 校验重试次数
if (executionCount >= MccConfigUtil.getHttpRetryTimes()) {
return false;
}
return true;
};
}
public static <T> T postJson(String url, int connectTimeOut, int socketTimeOut, Map<String, Object> params,
TypeReference<T> typeReference) {
// 构建httppost请求配置、实体、请求头
HttpPost httpPost = new HttpPost(url);
setPostConfig(httpPost, connectTimeOut, socketTimeOut);
setJsonData(httpPost, params);
// 发送post请求
CloseableHttpResponse response = null;
String result = "";
Stopwatch stopwatch = Stopwatch.createStarted();
try {
response = getHttpClient().execute(httpPost);
// 返回不为成功时直接返回null
if (response.getStatusLine().getStatusCode() != HttpStatus.SC_OK) {
log.error("HttpClientUtil.post, 发送POST请求获取响应, httpcode:{}, url:{}, connectTimeOut:{}, socketTimeOut:{}, params:{}",
response.getStatusLine().getStatusCode(), url, connectTimeOut, socketTimeOut, params);
return null;
}
HttpEntity entity = response.getEntity();
result = EntityUtils.toString(entity, CHARSET_UTF8);
return FastJsonUtils.parseObject(result, typeReference);
} catch (Exception e) {
log.error("HttpClientUtil.post, 执行POST请求失败, url:{}, connectTimeOut:{}, socketTimeOut:{}, params:{}, exception={}",
url, connectTimeOut, socketTimeOut, params, e);
return null;
} finally {
// 关闭响应
IOUtils.close(response);
log.info("HttpClientUtil.post, 发送POST请求的url:{}, param = {} , result = {}cost={}", url,
FastJsonUtils.toJSONString(params),
result,
stopwatch.elapsed(TimeUnit.MILLISECONDS));
}
}
private static void setJsonData(HttpPost httpPost, Map<String, Object> params) {
StringEntity entity = new StringEntity(FastJsonUtils.toJSONString(params),
"utf-8");//解决中文乱码问题
entity.setContentEncoding("UTF-8");
entity.setContentType("application/json");
httpPost.setEntity(entity);
}
}