package top.lvzhiqiang.util; import com.alibaba.fastjson.JSONException; import com.alibaba.fastjson.JSONObject; import org.apache.http.HttpResponse; import org.apache.http.HttpStatus; import org.apache.http.NameValuePair; import org.apache.http.client.config.RequestConfig; import org.apache.http.client.entity.UrlEncodedFormEntity; import org.apache.http.client.methods.*; import org.apache.http.client.utils.URIBuilder; import org.apache.http.client.utils.URLEncodedUtils; import org.apache.http.conn.ConnectionKeepAliveStrategy; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.DefaultConnectionKeepAliveStrategy; 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; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.net.URISyntaxException; import java.util.*; /** * HTTP工具类 * * @author shiyong * 2019-12-17 16:08 */ public class HttpUtils { // 编码格式。发送编码格式统一用UTF-8 private static final String ENCODING = "UTF-8"; // 设置连接超时时间,单位毫秒。ConnectTimeoutException private static final int CONNECT_TIMEOUT = 60000; // 请求获取数据的超时时间(即响应时间),单位毫秒。如果访问一个接口,多少时间内无法返回数据,就直接放弃此次调用。SocketTimeoutException private static final int SOCKET_TIMEOUT = 30000; // 设置从connect Manager获取Connection 超时时间,单位毫秒。这个属性是新加的属性,因为目前版本是可以共享连接池的。ConnectionPoolTimeout private static final int CONNECTION_REQUEST_TIMEOUT = 60000; private static final Logger log = LoggerFactory.getLogger(HttpUtils.class); private static CloseableHttpClient httpClient = null; /** * 自己构建httpclient连接池。通过享元模式来解决该问题来解决HttpClient引起的TCP连接数高问题 * * @return */ public static synchronized CloseableHttpClient getHttpClient() { if (httpClient == null) { PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager(); // 连接池最大连接数,默认为20 cm.setMaxTotal(2000); // 单条链路最大连接数(一个ip+一个端口是一个链路),即每个主机的最大连接数,默认为2 cm.setDefaultMaxPerRoute(1000); ConnectionKeepAliveStrategy kaStrategy = new DefaultConnectionKeepAliveStrategy() { @Override public long getKeepAliveDuration(HttpResponse response, HttpContext context) { long keepAlive = super.getKeepAliveDuration(response, context); if (keepAlive == -1) { keepAlive = 60000; } return keepAlive; } }; httpClient = HttpClients.custom().setConnectionManager(cm).setKeepAliveStrategy(kaStrategy).build(); } return httpClient; } /** * 发送get请求,返回字符串 * * @param url 请求地址 * @return java.lang.String * @author shiyong * 2020/4/15 10:54 */ public static String doGetToStr(String url) throws IOException, URISyntaxException { return doGetToStr(url, new HashMap<>()); } /** * 发送get请求,返回字符串 * * @param url 请求地址 * @param params 请求参数 * @return java.lang.String * @author shiyong * 2020/4/15 10:58 */ public static String doGetToStr(String url, Map params) throws IOException, URISyntaxException { return doGetToStr(url, new HashMap<>(), params); } /** * 发送get请求,返回字符串 * * @param url 请求地址 * @param headers 请求头 * @param params 请求参数 * @return java.lang.String * @author shiyong * 2020/4/15 10:59 */ public static String doGetToStr(String url, Map headers, Map params) throws IOException, URISyntaxException { // 创建httpClient对象 // CloseableHttpClient httpClient = HttpClients.createDefault(); CloseableHttpClient httpClient = getHttpClient(); // 创建httpResponse对象 CloseableHttpResponse httpResponse = null; HttpGet httpGet = null; try { // 创建访问的地址 URIBuilder uriBuilder = new URIBuilder(url); if (params != null) { Set> entrySet = params.entrySet(); for (Map.Entry entry : entrySet) { uriBuilder.setParameter(entry.getKey(), entry.getValue()); } } // 创建http对象 httpGet = new HttpGet(uriBuilder.build()); RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(CONNECT_TIMEOUT).setSocketTimeout(SOCKET_TIMEOUT).build(); httpGet.setConfig(requestConfig); // 设置请求头 packageHeader(headers, httpGet); // 执行请求 httpResponse = httpClient.execute(httpGet); if (null == httpResponse || null == httpResponse.getStatusLine() || null == httpResponse.getEntity() || httpResponse.getStatusLine().getStatusCode() != HttpStatus.SC_OK) { return ""; } return EntityUtils.toString(httpResponse.getEntity(), ENCODING); } catch (JSONException e) { throw new JSONException(e.getMessage()); } catch (IOException e) { throw new IOException(e); } finally { // 释放资源 if (httpGet != null) { httpGet.abort(); httpGet.releaseConnection(); } release(httpResponse, httpClient); } } /** * 发送post请求,返回字符串 * * @param url 请求地址 * @param headers 请求头 * @param params 请求参数 * @return java.lang.String * @author shiyong * 2020/4/15 11:35 */ public static String doPostToStr(String url, Map headers, Map params) throws IOException, JSONException { // 创建httpClient对象 // CloseableHttpClient httpClient = HttpClients.createDefault(); CloseableHttpClient httpClient = getHttpClient(); // 创建httpResponse对象 CloseableHttpResponse httpResponse = null; HttpPost httpPost = null; try { // 创建http对象 httpPost = new HttpPost(url); RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(CONNECT_TIMEOUT).setConnectionRequestTimeout(CONNECTION_REQUEST_TIMEOUT).setSocketTimeout(SOCKET_TIMEOUT).build(); httpPost.setConfig(requestConfig); //httpPost.setHeader(HttpHeaders.CONNECTION, "close"); packageHeader(headers, httpPost); // 封装请求参数 packageParam(params, httpPost); // 执行请求 httpResponse = httpClient.execute(httpPost); if (null == httpResponse || null == httpResponse.getStatusLine() || null == httpResponse.getEntity() || httpResponse.getStatusLine().getStatusCode() != HttpStatus.SC_OK) { return ""; } return EntityUtils.toString(httpResponse.getEntity(), ENCODING); } catch (JSONException e) { throw new JSONException(e.getMessage()); } catch (IOException e) { throw new IOException(e); } finally { // 释放资源 if (httpPost != null) { httpPost.abort(); httpPost.releaseConnection(); } release(httpResponse, httpClient); } } /** * 发送post请求,返回JSONObject * * @param url 请求地址 * @param params 参数集合 * @return com.alibaba.fastjson.JSONObject * @author shiyong * 2019/11/23 18:39 */ public static JSONObject doPost(String url, Map params) throws IOException { return doPost(url, new HashMap(), params); } /** * 发送post请求,返回JSONObject * * @param url 请求地址 * @param headers 请求头 * @param params 请求参数 * @return com.alibaba.fastjson.JSONObject * @author shiyong * 2019/11/23 18:35 */ public static JSONObject doPost(String url, Map headers, Map params) throws IOException { String content = doPostToStr(url, headers, params); if (StringUtils.isEmpty(content)) { return new JSONObject(); } return JSONObject.parseObject(content); } /** * 封装请求头 * * @param params 请求头 * @param httpMethod 请求方式 * @author shiyong * 2019/11/23 19:21 */ private static void packageHeader(Map params, HttpRequestBase httpMethod) { if (params != null) { Set> entrySet = params.entrySet(); for (Map.Entry entry : entrySet) { // 设置到请求头到HttpRequestBase对象中 httpMethod.setHeader(entry.getKey(), entry.getValue()); } } } /** * 封装请求参数 * * @param params 请求参数 * @param httpMethod 请求方式 * @author shiyong * 2019/11/23 19:22 */ private static void packageParam(Map params, HttpEntityEnclosingRequestBase httpMethod) throws UnsupportedEncodingException { if (params != null) { List nvps = new ArrayList<>(); Set> entrySet = params.entrySet(); for (Map.Entry entry : entrySet) { nvps.add(new BasicNameValuePair(entry.getKey(), entry.getValue())); } UrlEncodedFormEntity formEntity = new UrlEncodedFormEntity(nvps, ENCODING); formEntity.setContentType(URLEncodedUtils.CONTENT_TYPE); // 设置到请求的http对象中 httpMethod.setEntity(formEntity); } } /** * 释放资源 * * @param httpResponse HTTP响应 * @param httpClient HTTP客户端 * @author shiyong * 2019/11/23 19:28 */ private static void release(CloseableHttpResponse httpResponse, CloseableHttpClient httpClient) { try { if (httpResponse != null) { httpResponse.close(); } // 连接池使用的时候不能关闭连接,否则下次使用会抛异常 java.lang.IllegalStateException: Connection pool shut down // 选择使用连接池,就是将连接全部交由连接池管理,而我们在程序中使用了httpClient.close()就破坏了这以规则 /*if (httpClient != null) { httpClient.close(); }*/ } catch (IOException e) { log.error("释放HTTP请求资源失败!", e); } } }