package com.kdniao.logisticsfront.common.util.http; import org.apache.commons.lang.StringUtils; import org.apache.http.NameValuePair; import org.apache.http.NoHttpResponseException; 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.client.methods.HttpRequestBase; import org.apache.http.client.utils.URIBuilder; import org.apache.http.config.Registry; import org.apache.http.config.RegistryBuilder; import org.apache.http.config.SocketConfig; import org.apache.http.conn.DnsResolver; 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.ContentType; import org.apache.http.entity.StringEntity; import org.apache.http.impl.DefaultConnectionReuseStrategy; 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.DefaultHttpResponseParserFactory; import org.apache.http.impl.conn.ManagedHttpClientConnectionFactory; import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; import org.apache.http.impl.conn.SystemDefaultDnsResolver; import org.apache.http.impl.io.DefaultHttpRequestWriterFactory; import org.apache.http.message.BasicNameValuePair; import org.apache.http.ssl.SSLContextBuilder; import org.apache.http.util.EntityUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.InitializingBean; import org.springframework.util.CollectionUtils; import java.io.IOException; import java.net.URISyntaxException; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.concurrent.TimeUnit; public class HttpTest implements InitializingBean { protected static final Logger logger = LoggerFactory.getLogger("remote.digest"); protected String appName; protected CloseableHttpClient httpClient; protected String contentType = "application/x-www-form-urlencoded; charset=UTF-8"; protected Map<String, String> headerMap; protected String hostname; protected int readTimeout = 5000; protected int connectionTimeout = 5000; protected int maxTotalConnection = 5000; protected int retryCount = 0; protected String senderType; protected int validateAfterInactivityTime = 60000; private int maxPerRoute = 500; @Override public void afterPropertiesSet()throws Exception{ //创建http连接池 SSLContextBuilder builder = new SSLContextBuilder(); //忽略SSL协议 builder.loadTrustMaterial(null, (chain,authType)->{return true;}); /* (chain,authType)->{return true;} lambda 表达式方式 builder.loadTrustMaterial(null, new TrustStrategy(){ @Override public boolean isTrusted(X509Certificate[] chain, String authType){ return true; } }); builder.loadTrustMaterial(null, (chain,authType)->{return true;}); 上面两端代码含义一致 */ SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(builder.build(), NoopHostnameVerifier.INSTANCE); //注册访问协议相关的Socket工厂 Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory>create().register("http", PlainConnectionSocketFactory.INSTANCE) .register("https", sslsf).build(); //HttpConnection 工厂:配置写请求/解析响应处理器 ManagedHttpClientConnectionFactory connFactory = new ManagedHttpClientConnectionFactory(DefaultHttpRequestWriterFactory.INSTANCE, DefaultHttpResponseParserFactory.INSTANCE); //DNS 解析器 DnsResolver dnsResolver = SystemDefaultDnsResolver.INSTANCE; //连接池 PoolingHttpClientConnectionManager manager = new PoolingHttpClientConnectionManager(socketFactoryRegistry, connFactory, dnsResolver); //默认为Socket配置 // TcpNoDelay是否立即发送数据,设置为true会关闭Socket缓冲,默认为false SocketConfig socketConfig = SocketConfig.custom().setTcpNoDelay(true).build(); manager.setDefaultSocketConfig(socketConfig); manager.setMaxTotal(maxTotalConnection); //设置整个连接池的最大连接数 manager.setDefaultMaxPerRoute(maxPerRoute);//每个路由的最大连接数 manager.setValidateAfterInactivity(validateAfterInactivityTime); //在从连接池获取连接时,连接不活跃多长时间后需要进行一次验证,默认为2s //默认请求配置 RequestConfig defaulRequestConfig = RequestConfig.custom() .setConnectTimeout(connectionTimeout) //设置连接超时时间 .setSocketTimeout(readTimeout) //设置等待数据超时时间,5s .setConnectionRequestTimeout(connectionTimeout) .build(); httpClient = HttpClients.custom() .setConnectionManager(manager) .setConnectionManagerShared(false)//连接池不是共享模式 .evictIdleConnections(60, TimeUnit.SECONDS) //定期回收空闲连接 .evictExpiredConnections() // 定期回收过期连接 .setConnectionTimeToLive(60, TimeUnit.SECONDS)//连接存活时间,如果不设置,则根据长连接信息决定 .setDefaultRequestConfig(defaulRequestConfig)//设置默认请求配置 .setConnectionReuseStrategy(DefaultConnectionReuseStrategy.INSTANCE)//连接重用策略,即是否能keepAlive .setKeepAliveStrategy(DefaultConnectionKeepAliveStrategy.INSTANCE)//长连接配置,即获取长连接生产多长时间 .setRetryHandler((exception, executionCount, context)->{ //设置重试 lambda 表达式方式 if(executionCount>2){ return false; } if(exception instanceof NoHttpResponseException){ logger.warn("NoHttpResponseException on"+executionCount+"call"); return true; } return false; }) .build(); //jvm 虚拟机关闭时执行 关闭http线程池 Runtime.getRuntime().addShutdownHook(new Thread() { @Override public void run() { try { httpClient.close(); } catch (IOException e) { e.printStackTrace(); } } }); } /** * http 请求 * @param path url 请求路径 * @param paramMap get 请求参数 * @param body post 请求参数 字符串类型 * @param method 请求方式 post get * @param formMap post请求参数 map类型 * @return */ public String send(String path, Map<String, String> paramMap, String body, String method, Map<String, String> formMap) { // HttpClients 创建连接步骤 //1.使用帮助类HttpClients创建CloseableHttpClient对象. //2. 基于要发送的HTTP请求类型创建HttpGet或者HttpPost实例. //3. 使用addHeader方法添加请求头部,诸如User-Agent, Accept-Encoding等参数. //4. 对于POST请求,创建NameValuePair列表,并添加所有的表单参数.然后把它填充进HttpPost实体. //5. 通过执行此HttpGet或者HttpPost请求获取CloseableHttpResponse实例 //6. 从此CloseableHttpResponse实例中获取状态码,错误信息,以及响应页面等等. //7. 最后关闭HttpClient资源. //1、通过线程池创建CloseableHttpClient对象 httpClient HttpRequestBase request = null; URIBuilder uriBuilder = null; try { uriBuilder = new URIBuilder(hostname); //hostname 配置文件配置的默认url } catch (URISyntaxException urise) { System.out.println("url语法错误:" + urise); } if (!StringUtils.isEmpty(path)) { uriBuilder.setPath(path); } if (!CollectionUtils.isEmpty(paramMap)) { //设置请求参数 例子:url&use=1 for (String paramName : paramMap.keySet()) { uriBuilder.addParameter(paramName, paramMap.get(paramName)); } } String url = uriBuilder.toString(); try { if (HttpGet.METHOD_NAME.equals(method)) { HttpGet httpGet = new HttpGet(url); request = httpGet; } else if (HttpPost.METHOD_NAME.equals(method)) { HttpPost httpPost = new HttpPost(url); if (StringUtils.isEmpty(body) && null != formMap) { List<NameValuePair> paramList = new ArrayList<>(); for (String key : formMap.keySet()) { paramList.add(new BasicNameValuePair(key, formMap.get(key))); } //通过list形式来添加参数 httpPost.setEntity(new UrlEncodedFormEntity(paramList, "utf-8")); } else { //通过string形式传参 httpPost.setEntity(new StringEntity(body, ContentType.create(contentType))); } request = httpPost; } else { System.out.println("不支持的http method[" + method + "]"); } //设置表头 if (!CollectionUtils.isEmpty(headerMap)) { for (String headerName : headerMap.keySet()) { request.addHeader(headerName, headerMap.get(headerName)); } } } catch (Exception e1) { System.out.println("Unsupported http exception:"+ e1); } String responseString = null; try { //创建连接 CloseableHttpResponse response = httpClient.execute(request); //返回结果 responseString = EntityUtils.toString(response.getEntity(), "UTF-8"); } catch (Exception e) { //ioe = e ; System.out.println("http invoke exception:" + e.getMessage()); } finally { //链接并没有关闭 只是将链接还给连接池 request.releaseConnection(); //程序终止 request.abort(); /* DefaultDigestLogBuilder logBuilder = new DefaultDigestLogBuilder(); logBuilder.setRequestId(cxt != null ? cxt.getRequestId() : null); logBuilder.setAppName(appName); logBuilder.setStartTime(new Date(startTime)); logBuilder.setUri(url); logBuilder.setLocalIp(SystemUtils.hostInfo.getHostAddress()); //logBuilder.setRemoteIp(RpcContext.getContext().getRemoteAddressString()); // 只有系统不可用导致的错误为调用失败 logBuilder.setSuccess(success); logBuilder.setError(ioe == null ? null : GatewayErrors.invoke3thFailed.message(ioe.getMessage())); logBuilder.setParameters(new Object[]{method, paramMap, body,formMap}); logBuilder.setResult(responseString); logBuilder.setElapseTime(endTime - startTime);*/ } //返回结果 return responseString; } }