|
|
@@ -0,0 +1,326 @@
|
|
|
+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<String, String> 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<String, String> headers, Map<String, String> 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<Map.Entry<String, String>> entrySet = params.entrySet();
|
|
|
+
|
|
|
+ for (Map.Entry<String, String> 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<String, String> headers, Map<String, String> 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<String, String> params) throws IOException {
|
|
|
+ return doPost(url, new HashMap<String, String>(), 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<String, String> headers, Map<String, String> 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<String, String> params, HttpRequestBase httpMethod) {
|
|
|
+ if (params != null) {
|
|
|
+ Set<Map.Entry<String, String>> entrySet = params.entrySet();
|
|
|
+
|
|
|
+ for (Map.Entry<String, String> 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<String, String> params, HttpEntityEnclosingRequestBase httpMethod) throws UnsupportedEncodingException {
|
|
|
+ if (params != null) {
|
|
|
+ List<NameValuePair> nvps = new ArrayList<>();
|
|
|
+
|
|
|
+ Set<Map.Entry<String, String>> entrySet = params.entrySet();
|
|
|
+
|
|
|
+ for (Map.Entry<String, String> 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);
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+}
|