package com.tzld.piaoquan.featurestools.util; import com.google.common.collect.Lists; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.concurrent.BasicThreadFactory; import org.apache.http.HttpEntity; import org.apache.http.HttpRequestInterceptor; import org.apache.http.HttpStatus; import org.apache.http.client.config.RequestConfig; import org.apache.http.client.methods.*; 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.PlainConnectionSocketFactory; import org.apache.http.conn.ssl.NoopHostnameVerifier; import org.apache.http.conn.ssl.SSLConnectionSocketFactory; import org.apache.http.entity.StringEntity; import org.apache.http.entity.mime.MultipartEntityBuilder; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.DefaultHttpRequestRetryHandler; import org.apache.http.impl.client.HttpClientBuilder; import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; import org.apache.http.ssl.SSLContexts; import org.apache.http.util.EntityUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.slf4j.MDC; import javax.net.ssl.SSLContext; import java.io.File; import java.io.IOException; import java.net.SocketTimeoutException; import java.nio.charset.StandardCharsets; import java.security.KeyManagementException; import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; import java.util.List; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledThreadPoolExecutor; import java.util.concurrent.TimeUnit; /** * http client * * @author xueyiming */ public class HttpPoolClientUtil { private static final Logger LOGGER = LoggerFactory.getLogger(HttpPoolClientUtil.class); private static final ScheduledExecutorService SCHEDULED_CLOSED_EXECUTOR = new ScheduledThreadPoolExecutor(1, new BasicThreadFactory.Builder().namingPattern("http conn-closed-thread-%s").priority(Thread.NORM_PRIORITY).daemon(false).build(), (r, e) -> LOGGER.error(" monitor push reject task error={}", e.toString())); private static final List HTTP_CLIENT_CONNECTION_MANAGERS = Lists.newArrayList(); static { SCHEDULED_CLOSED_EXECUTOR.schedule(() -> HTTP_CLIENT_CONNECTION_MANAGERS.forEach(HttpClientConnectionManager::closeExpiredConnections), 5, TimeUnit.SECONDS); } private CloseableHttpClient closeableHttpClient; private HttpPoolClientUtil(CloseableHttpClient closeableHttpClient) { this.closeableHttpClient = closeableHttpClient; } private static HttpRequestInterceptor getInterceptor() { HttpRequestInterceptor requestInterceptor = (request, context) -> { try { String missSpanId = MDC.get("missSpanId"); String missTraceId = MDC.get("request-id"); if (missTraceId != null && !"".equals(missTraceId.trim())) { request.setHeader("request-id", missTraceId); } if (missSpanId != null && !"".equals(missSpanId.trim())) { request.setHeader("missSpanId", missSpanId); } } catch (Exception e) { LOGGER.error(e.getMessage(), e); } }; return requestInterceptor; } public String get(String url) throws IOException { HttpGet httpGet = new HttpGet(url); return request(httpGet); } public String post(String url) throws IOException { HttpPost httpPost = new HttpPost(url); return request(httpPost); } public String post(String url, String json) throws IOException { HttpPost httpPost = new HttpPost(url); if (StringUtils.isBlank(json)) { return request(httpPost); } StringEntity entity = new StringEntity(json, StandardCharsets.UTF_8); entity.setContentEncoding("UTF-8"); entity.setContentType("application/json"); httpPost.setEntity(entity); return request(httpPost); } public String post(String url, File file) throws IOException { HttpPost uploadFile = new HttpPost(url); MultipartEntityBuilder builder = MultipartEntityBuilder.create(); builder.addBinaryBody("media", file); uploadFile.setEntity(builder.build()); return request(uploadFile); } public String request(HttpRequestBase request) throws IOException { if (LOGGER.isDebugEnabled()) { String path = request.getURI().toString(); LOGGER.debug("http request url = {} ", path); } HttpEntity entity = null; CloseableHttpResponse response = request((HttpUriRequest) request); if (response == null) { throw new RuntimeException("call api exception no response"); } entity = response.getEntity(); String content = null; if (entity != null) { content = EntityUtils.toString(entity, "UTF-8"); } int httpStatus = response.getStatusLine().getStatusCode(); if (httpStatus == HttpStatus.SC_OK) { return content; } String path = request.getURI().toString(); LOGGER.error("http call api {} fail response status {} content {}", path, httpStatus, content); // throw new HttpServiceException(httpStatus, content); return null; } public CloseableHttpResponse request(HttpUriRequest request) { try { CloseableHttpResponse execute = closeableHttpClient.execute(request); return execute; } catch (Exception e) { String path = request.getURI().toString(); if (e instanceof SocketTimeoutException) { LOGGER.error(String.format("http timeout request url = %s .", path)); // throw new TimeoutException(); } else { } throw new RuntimeException(String.format("http exception request url = %s ", path), e); } } /** * @param connectTimeout 连接超时时间 ms * @param socketTimeout 读超时时间(等待数据超时时间)ms * @param maxPerRoute 每个路由的最大连接数 * @param maxTotal 最大连接数 * @param retryCount 重试次数 * @return httpclient instance */ public static HttpPoolClientUtil create(int connectTimeout, int socketTimeout, int maxPerRoute, int maxTotal, int retryCount, int connectionWaitTimeout) { try { RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(connectTimeout).setSocketTimeout(socketTimeout).setConnectionRequestTimeout(connectionWaitTimeout).build(); CloseableHttpClient client = HttpClientBuilder.create() .setDefaultRequestConfig(requestConfig) .setConnectionManager(createConnectionManager(maxPerRoute, maxTotal)) .setRetryHandler(new DefaultHttpRequestRetryHandler(retryCount, false)).addInterceptorFirst(getInterceptor()).build(); return new HttpPoolClientUtil(client); } catch (Throwable e) { LOGGER.error("create HttpPoolClient exception", e); throw new RuntimeException("create HttpPoolClient exception"); } } private static PoolingHttpClientConnectionManager createConnectionManager(int maxPerRoute, int maxTotal) throws NoSuchAlgorithmException, KeyStoreException, KeyManagementException { SSLContext sslContext = SSLContexts.custom().loadTrustMaterial((chain, authType) -> true).build(); Registry registry = RegistryBuilder.create() .register("http", PlainConnectionSocketFactory.getSocketFactory()) .register("https", new SSLConnectionSocketFactory(sslContext, NoopHostnameVerifier.INSTANCE)).build(); PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager(registry); cm.setDefaultMaxPerRoute(maxPerRoute); cm.setMaxTotal(maxTotal); HTTP_CLIENT_CONNECTION_MANAGERS.add(cm); return cm; } }