httpclient封装,基于httpclient5
参考:
http://www.mydlq.club/article/68/
feign的apache hc5封装
apache hc5官网
https://hc.apache.org/httpcomponents-client-5.2.x/migration-guide/migration-to-classic.html
有一说一。。。hc的可参考相关资料是真的少,都是各写各的。。。官网的example界面甚至全部404,一股草台风铺面而来。如果大量的调用时内部调用,建议还是用feign,别自己封了
import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.StringJoiner;
import java.util.concurrent.TimeUnit;
import org.apache.hc.client5.http.classic.methods.HttpGet;
import org.apache.hc.client5.http.classic.methods.HttpPost;
import org.apache.hc.client5.http.classic.methods.HttpUriRequestBase;
import org.apache.hc.client5.http.config.RequestConfig;
import org.apache.hc.client5.http.cookie.BasicCookieStore;
import org.apache.hc.client5.http.cookie.CookieStore;
import org.apache.hc.client5.http.entity.UrlEncodedFormEntity;
import org.apache.hc.client5.http.impl.auth.BasicCredentialsProvider;
import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
import org.apache.hc.client5.http.impl.classic.CloseableHttpResponse;
import org.apache.hc.client5.http.impl.classic.HttpClients;
import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManager;
import org.apache.hc.client5.http.socket.ConnectionSocketFactory;
import org.apache.hc.client5.http.socket.PlainConnectionSocketFactory;
import org.apache.hc.client5.http.ssl.SSLConnectionSocketFactory;
import org.apache.hc.core5.http.ContentType;
import org.apache.hc.core5.http.NameValuePair;
import org.apache.hc.core5.http.config.Registry;
import org.apache.hc.core5.http.config.RegistryBuilder;
import org.apache.hc.core5.http.io.SocketConfig;
import org.apache.hc.core5.http.io.entity.EntityUtils;
import org.apache.hc.core5.http.io.entity.StringEntity;
import org.apache.hc.core5.http.message.BasicNameValuePair;
import org.apache.hc.core5.util.TimeValue;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* 创建httpClient工具类
*/
public class HttpClientUtil {
private static final Logger LOGGER = LoggerFactory.getLogger(HttpClientUtil.class);
/**
* HttpClient 对象
*/
private static CloseableHttpClient httpClient;
/**
* CookieStore 对象
*/
private static final CookieStore cookieStore;
/**
* Basic Auth 管理对象
*/
private static final BasicCredentialsProvider basicCredentialsProvider;
/**
* 默认响应的字符编码
*/
private static final Charset DEFAULT_CHARSET = StandardCharsets.UTF_8;
private static final int DEFAULT_MAX_TOTAL = 200;
private static final int DEFAULT_MAX_PER_ROUTE = 200;
static {
// 注册访问协议相关的 Socket 工厂
Registry<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory>create()
.register("http", PlainConnectionSocketFactory.getSocketFactory())
.register("https", SSLConnectionSocketFactory.getSocketFactory())
.build();
// Http 连接池
PoolingHttpClientConnectionManager poolingHttpClientConnectionManager =
new PoolingHttpClientConnectionManager(registry);
poolingHttpClientConnectionManager.setDefaultSocketConfig(SocketConfig.custom()
.setSoTimeout(30, TimeUnit.SECONDS)
// tcpNodelay不开启, 此client几乎不用于频繁交互且数据量小的情况
//.setTcpNoDelay(true)
.build()
);
poolingHttpClientConnectionManager.setMaxTotal(DEFAULT_MAX_TOTAL);
poolingHttpClientConnectionManager.setDefaultMaxPerRoute(DEFAULT_MAX_PER_ROUTE);
// 在从连接池获取连接时,连接不活跃多长时间后需要进行一次验证
poolingHttpClientConnectionManager.setValidateAfterInactivity(TimeValue.ofSeconds(5));
// Http 默认请求配置
RequestConfig requestConfig = RequestConfig.custom()
.setConnectTimeout(5000, TimeUnit.MILLISECONDS)
.setResponseTimeout(5000, TimeUnit.MILLISECONDS)
.setConnectionRequestTimeout(5000, TimeUnit.MILLISECONDS)
.build();
// 设置 Cookie
cookieStore = new BasicCookieStore();
// 设置 Basic Auth 对象
basicCredentialsProvider = new BasicCredentialsProvider();
// 创建监听器,在 JVM 停止或重启时,关闭连接池释放掉连接
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
try {
LOGGER.info("执行关闭 HttpClient");
httpClient.close();
LOGGER.info("已经关闭 HttpClient");
} catch (IOException e) {
LOGGER.error("HttpClient关闭异常", e);
}
}));
// 创建 HttpClient 对象
httpClient = HttpClients.custom()
// 设置 Cookie
.setDefaultCookieStore(cookieStore)
// 设置 Basic Auth
.setDefaultCredentialsProvider(basicCredentialsProvider)
// 设置 HttpClient 请求参数
.setDefaultRequestConfig(requestConfig)
// 设置连接池
.setConnectionManager(poolingHttpClientConnectionManager)
// 设置定时清理连接池中过期的连接, 设置这个一定要保证httpclient是单例或者数量一定的!!!
.evictExpiredConnections()
.evictIdleConnections(TimeValue.ofMinutes(3))
.build();
}
private HttpClientUtil() {
}
/**
* 获取 Httpclient 对象
*
* @return CloseableHttpClient
*/
public static CloseableHttpClient getHttpclient() {
return httpClient;
}
/**
* 获取 CookieStore 对象
*
* @return CookieStore
*/
private static CookieStore getCookieStore() {
return cookieStore;
}
/**
* 获取 BasicCredentialsProvider 对象
*
* @return BasicCredentialsProvider
*/
private static BasicCredentialsProvider getBasicCredentialsProvider() {
return basicCredentialsProvider;
}
/**
* get请求
* @param url
* @return
*/
public static String get(String url) {
return get(url, 0);
}
/**
* get请求
* @param url
* @param timeout 超时时间(毫秒)
* @return
*/
public static String get(String url, int timeout) {
return getWithParams(url, null, timeout);
}
/**
* get请求带参数集合
* @param url 基础url(没带参数), 如果想自己拼接带参数的url, params需要传null或者空
* @param params 按照key=value拼接到url上
* @param timeout 超时时间(毫秒)
* @return
*/
public static String getWithParams(String url, Map<String, String> params, int timeout) {
return get(url, null, params, timeout);
}
/**
* get请求带header
* @param url
* @param header header, 若无传null或空集
* @param timeout 超时时间(毫秒)
* @return
*/
public static String getWithHeader(String url, Map<String, String> header, int timeout) {
return get(url, header, null, timeout);
}
/**
* get请求
* @param url 基础url(没带参数), 如果想自己拼接带参数的url, params需要传null或者空
* @param header header, 若无传null或空集
* @param params 传递参数, 将按照key=value拼接到url上, 若无传null或者空集
* @param timeout 超时时间(毫秒)
* @return 响应内容
*/
public static String get(String url, Map<String, String> header, Map<String, String> params, int timeout){
return send(url, HttpGet.METHOD_NAME, null, header, params, timeout);
}
/**
* post 表单请求
* @param url
* @param params 表单参数, 若无传null或空集
* @return 响应内容
*/
public static String postForm(String url, Map<String, String> params) {
return postForm(url, params, 0);
}
/**
* post 表单请求
* @param url
* @param params 表单参数, 若无传null或空集
* @param timeout 超时时间(毫秒)
* @return 响应内容
*/
public static String postForm(String url, Map<String, String> params, int timeout) {
return postForm(url, null, params, timeout);
}
/**
* post 表单请求
* @param url
* @param header header, 若无传null或空集
* @param params 表单参数, 若无传null或空集
* @param timeout 超时时间(毫秒)
* @return 响应内容
*/
public static String postForm(String url, Map<String, String> header, Map<String, String> params, int timeout) {
return send(url, HttpPost.METHOD_NAME, ContentType.APPLICATION_FORM_URLENCODED, header, params, timeout);
}
/**
* post json请求
* @param url
* @param json json字符串, 若无传null或者空字符串
* @return 响应内容
*/
public static String postJson(String url, String json) {
return postJson(url, json, 0);
}
/**
* post json请求
* @param url
* @param json json字符串, 若无传null或者空字符串
* @param timeout 超时时间(毫秒)
* @return 响应内容
*/
public static String postJson(String url, String json, int timeout) {
return postJson(url, null, json, timeout);
}
/**
* post json请求
* @param url
* @param header header, 若无传null或空集
* @param json json字符串, 若无传null或者空字符串
* @param timeout 超时时间(毫秒)
* @return 响应内容
*/
public static String postJson(String url, Map<String, String> header, String json, int timeout) {
return send(url, HttpPost.METHOD_NAME, ContentType.APPLICATION_JSON, header, json, timeout);
}
private static String send(String url, String methodName, ContentType contentType, Map<String, String> header,
Object content, int timeout) {
HttpUriRequestBase request = buildRequest(url, methodName, content);
addHeader(request, contentType, header);
setRequestConfig(request, timeout);
setContent(request, contentType, content);
return getResponse(request);
}
private static String getResponse(HttpUriRequestBase request) {
// 发起请求
try(CloseableHttpResponse response = httpClient.execute(request)){
LOGGER.info("httpclient response code: {} - {}", response.getCode(), response.getReasonPhrase());
// 注意这里的response长度不能超过Integer的最大值(可以自定义, 这里使用是默认值)
String responseContent = EntityUtils.toString(response.getEntity(), DEFAULT_CHARSET);
// 确保完全消费
EntityUtils.consume(response.getEntity());
return responseContent;
} catch (Exception e) {
// todo 自定义异常
throw new RuntimeException(e);
}
}
/**
* 构建请求
* @param url
* @param methodName
* @param content get请求为params, 按照?key1=value1&key2=value2拼接, post请求直接设置url
* @return
*/
private static HttpUriRequestBase buildRequest(String url, String methodName, Object content) {
if (HttpGet.METHOD_NAME.equals(methodName)) {
Map<String, String> params = (Map<String, String>)content;
if (params == null || params.isEmpty()){
return new HttpGet(url);
}else {
StringJoiner urlJoiner = new StringJoiner("&");
for (Map.Entry<String, String> param : params.entrySet()) {
urlJoiner.add(param.getKey() + "=" + param.getValue());
}
return new HttpGet(url + "?" + urlJoiner);
}
}
if (HttpPost.METHOD_NAME.equals(methodName)) {
return new HttpPost(url);
}
return null;
}
private static void addHeader(HttpUriRequestBase request, ContentType contentType, Map<String, String> header) {
// post请求设置contentType请求头
if (request instanceof HttpPost) {
request.addHeader("Content-Type", contentType.getMimeType());
}
if (header == null || header.isEmpty()) {
return;
}
for (Map.Entry<String, String> headerEntry : header.entrySet()) {
request.addHeader(headerEntry.getKey(), headerEntry.getValue());
}
}
private static void setRequestConfig(HttpUriRequestBase request, int timeout) {
// timeout为0走默认配置
if (timeout == 0) {
return;
}
RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(timeout, TimeUnit.MILLISECONDS)
.setResponseTimeout(timeout, TimeUnit.MILLISECONDS)
.setConnectionRequestTimeout(timeout, TimeUnit.MILLISECONDS).build();
request.setConfig(requestConfig);
}
private static void setContent(HttpUriRequestBase request, ContentType contentType, Object content) {
if (contentType == null || content == null) {
return;
}
if (ContentType.APPLICATION_FORM_URLENCODED == contentType) {
List<NameValuePair> paramList = new ArrayList<>();
Map<String, String> contentMap = (Map<String, String>) content;
if (contentMap.isEmpty()) {
return;
}
for (Map.Entry<String, String> entry : contentMap.entrySet()) {
paramList.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));
}
request.setEntity(new UrlEncodedFormEntity(paramList, DEFAULT_CHARSET));
}else if (ContentType.APPLICATION_JSON == contentType) {
if (((String)content).isEmpty()) {
return;
}
request.setEntity(new StringEntity((String) content, DEFAULT_CHARSET));
}
}
}