• springboot2.X集成HttpClient 发送HTTPS 请求


    1)jar

     <!--httpclient  发送外部https/http 请求-->
            <dependency>
                <groupId>org.apache.httpcomponents</groupId>
                <artifactId>httpclient</artifactId>
            </dependency>
            <dependency>
                <groupId>org.apache.httpcomponents</groupId>
                <artifactId>httpcore</artifactId>
            </dependency>
            <dependency>
                <groupId>commons-codec</groupId>
                <artifactId>commons-codec</artifactId>
                <version>1.11</version>
            </dependency>

    2)配置

    httpclient:
      maxTotal: 300
      defaultMaxPerRoute: 100
      connectTimeout: 1000
      connectionRequestTimeout: 500
      socketTimeout: 100000000
      staleConnectionCheckEnabled: true
      #  keyStorePath: C:/Users/Administrator/Desktop/广州办映射服务器测试证书20181010/dakehu/keystore.jks #证书路径
      keyStorePath: /usr/https_cert/keystore.jks #证书路径
      keyStorepass: 123456 #证书密码`

    3)编写 HttpClient 集成相应的配置

    package com.bigcustomer.utils.httpUtil;
    
    import lombok.Data;
    import org.apache.http.client.config.RequestConfig;
    import org.apache.http.config.Registry;
    import org.apache.http.config.RegistryBuilder;
    import org.apache.http.conn.socket.ConnectionSocketFactory;
    import org.apache.http.conn.socket.PlainConnectionSocketFactory;
    import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
    import org.apache.http.impl.client.CloseableHttpClient;
    import org.apache.http.impl.client.HttpClientBuilder;
    import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
    import org.apache.http.ssl.SSLContexts;
    import org.springframework.beans.factory.annotation.Qualifier;
    import org.springframework.boot.context.properties.ConfigurationProperties;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    
    import javax.net.ssl.SSLContext;
    import java.io.File;
    import java.io.FileInputStream;
    import java.io.IOException;
    import java.security.KeyStore;
    
    /**
     * @author :CX
     * @Date :Create in 2018/8/17 9:57
     * @Effect :
     */
    @Data
    @Configuration
    @ConfigurationProperties(prefix = "httpclient")
    public class HttpClient {
    
    
        private Integer maxTotal;
    
        private Integer defaultMaxPerRoute;
    
        private Integer connectTimeout;
    
        private Integer connectionRequestTimeout;
    
        private Integer socketTimeout;
    
        private boolean staleConnectionCheckEnabled;
    
        //https 证书 路径
        private String keyStorePath;
        // 证书密码
        private String keyStorepass;
    
        @Bean(name = "sslcontext")
        public SSLContext getSslcontext() {
            SSLContext sc = null;
            FileInputStream instream = null;
            KeyStore trustStore = null;
            try {
                trustStore = KeyStore.getInstance("JKS");
                instream = new FileInputStream(new File(keyStorePath));
                trustStore.load(instream, keyStorepass.toCharArray());
                // 相信自己的CA和所有自签名的证书
                sc = SSLContexts.custom().loadKeyMaterial(trustStore, keyStorepass.toCharArray()).build();
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                try {
                    instream.close();
                } catch (IOException e) {
                }
            }
            return sc;
        }
    
        /**
         * 首先实例化一个连接池管理器,设置最大连接数、并发连接数
         *
         * @return
         */
        @Bean(name = "httpClientConnectionManager")
        public PoolingHttpClientConnectionManager getHttpClientConnectionManager(@Qualifier("sslcontext") SSLContext sslcontext) {
            // 设置协议http和https对应的处理socket链接工厂的对象
            Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory>create()
                    .register("http", PlainConnectionSocketFactory.INSTANCE)
                    .register("https", new SSLConnectionSocketFactory(sslcontext))
                    .build();
            PoolingHttpClientConnectionManager httpClientConnectionManager =
                    new PoolingHttpClientConnectionManager(socketFactoryRegistry);
    //最大连接数
            httpClientConnectionManager.setMaxTotal(maxTotal);
    //并发数
            httpClientConnectionManager.setDefaultMaxPerRoute(defaultMaxPerRoute);
            return httpClientConnectionManager;
        }
    
        /**
         * 实例化连接池,设置连接池管理器。
         * 这里需要以参数形式注入上面实例化的连接池管理器
         *
         * @param httpClientConnectionManager
         * @return
         */
        @Bean(name = "httpClientBuilder")
        public HttpClientBuilder getHttpClientBuilder(@Qualifier("httpClientConnectionManager") PoolingHttpClientConnectionManager httpClientConnectionManager) {
    
    //HttpClientBuilder中的构造方法被protected修饰,所以这里不能直接使用new来实例化一个HttpClientBuilder,可以使用HttpClientBuilder提供的静态方法create()来获取HttpClientBuilder对象
            HttpClientBuilder httpClientBuilder = HttpClientBuilder.create();
    
            httpClientBuilder.setConnectionManager(httpClientConnectionManager);
    
            return httpClientBuilder;
        }
    
        /**
         * 注入连接池,用于获取httpClient
         *
         * @param httpClientBuilder
         * @return
         */
        @Bean
        public CloseableHttpClient getCloseableHttpClient(@Qualifier("httpClientBuilder") HttpClientBuilder httpClientBuilder) {
            return httpClientBuilder.build();
        }
    
        /**
         * Builder是RequestConfig的一个内部类
         * 通过RequestConfig的custom方法来获取到一个Builder对象
         * 设置builder的连接信息
         * 这里还可以设置proxy,cookieSpec等属性。有需要的话可以在此设置
         *
         * @return
         */
        @Bean(name = "builder")
        public RequestConfig.Builder getBuilder() {
            RequestConfig.Builder builder = RequestConfig.custom();
            return builder.setConnectTimeout(connectTimeout)
                    .setConnectionRequestTimeout(connectionRequestTimeout)
                    .setSocketTimeout(socketTimeout)
                    .setStaleConnectionCheckEnabled(staleConnectionCheckEnabled);
        }
    
        /**
         * 使用builder构建一个RequestConfig对象
         *
         * @param builder
         * @return
         */
        @Bean(name = "requestConfig")
        public RequestConfig getRequestConfig(@Qualifier("builder") RequestConfig.Builder builder) {
    
            return builder.build();
    
        }
    
    }

    4)编写定时回收无效资源的类

    package com.bigcustomer.utils.httpUtil;
    
    import org.apache.http.conn.HttpClientConnectionManager;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Component;
    
    /**
     * @author :CX
     * @Date :Create in 2018/8/17 10:00
     * @Effect : 定时回收没有使用的链接 交还给连接池
     */
    @Component
    public class IdleConnectionEvictor extends Thread {
    
        @Autowired
        private HttpClientConnectionManager httpClientConnectionManager;
        private volatile boolean shutdown;
    
        public IdleConnectionEvictor() {
            super();
            super.start();
        }
    
        @Override
        public void run() {
            try {
                while (!shutdown) {
                    synchronized (this) {
                        wait(5000);
    // 关闭失效的连接
                        httpClientConnectionManager.closeExpiredConnections();
                    }
                }
            } catch (InterruptedException ex) {
    // 结束
            }
        }
    
        //关闭清理无效连接的线程
        public void shutdown() {
            shutdown = true;
            synchronized (this) {
                notifyAll();
            }
        }
    }

    5) 工具类

    package com.bigcustomer.utils.httpUtil;
    
    import com.alibaba.fastjson.JSON;
    import com.alibaba.fastjson.parser.Feature;
    import com.bigcustomer.configs.BaseConfig;
    import com.bigcustomer.configs.KeyConfig;
    import com.bigcustomer.utils.ExternalHelpUtile;
    import com.bigcustomer.utils.SinUtil;
    import huashitech.kissucomponent.redis.RedisUtil;
    import org.apache.http.HttpEntity;
    import org.apache.http.client.ClientProtocolException;
    import org.apache.http.client.config.RequestConfig;
    import org.apache.http.client.methods.CloseableHttpResponse;
    import org.apache.http.client.methods.HttpPost;
    import org.apache.http.entity.StringEntity;
    import org.apache.http.impl.client.CloseableHttpClient;
    import org.apache.http.util.EntityUtils;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Component;
    
    import java.io.IOException;
    import java.util.LinkedHashMap;
    import java.util.Map;
    
    
    /**
     * @author :CX
     * @Date :Create in 2018/8/17 10:02
     * @Effect :
     */
    @Component
    public class HttpsUtils {
        private static Logger logger = LoggerFactory.getLogger(HttpsUtils.class);
        static CloseableHttpClient httpClient;
        static RequestConfig requestConfig;
        static CloseableHttpResponse httpResponse;
    
        private static BaseConfig baseConfig;
        private static ExternalHelpUtile utile;
        private static KeyConfig config;
        private static SinUtil sinUtil;
        private static RedisUtil redisUtil;
        private static String encoding = "utf-8";
    
        @Autowired
        public void init(KeyConfig config, BaseConfig baseConfig, RedisUtil redisUtil,
                         ExternalHelpUtile utile, SinUtil sinUtil,
                         CloseableHttpClient httpClient
                       , RequestConfig requestConfig) {
            HttpsUtils.config = config;
            HttpsUtils.baseConfig = baseConfig;
            HttpsUtils.redisUtil = redisUtil;
            HttpsUtils.utile = utile;
            HttpsUtils.sinUtil = sinUtil;
            HttpsUtils.httpClient = httpClient;
            HttpsUtils.requestConfig = requestConfig;
    
        }
    
       //https 封装方法
        private static Map<String , Object> baseSendHttpsPost(Map<String, Object> par, String url, String key) throws ClientProtocolException, IOException {
            //请求map
            LinkedHashMap<String, Object> requestMap = new LinkedHashMap<>();
            requestMap.put("mac", null);// 签名会去掉mac
            requestMap.put("agentcode", config.getAgentcode());
            requestMap.put("msgbody", par);
    
            // 签名并对mac 重新赋值
            String mac = sinUtil.createMac(requestMap, key);
            requestMap.put("mac", mac);
            String parStr = JSON.toJSONString(requestMap);
            logger.info("参数 :" + parStr);
            try {
    
                //创建post方式请求对象
                HttpPost httpPost = new HttpPost(url);
    
                //装填参数
                StringEntity stringEntity = null;
                if (null != par) {
                    stringEntity = new StringEntity(parStr,encoding);
                    httpPost.setEntity(stringEntity);
                }
    
                logger.info("创建请求httpsPost-URL={},params={}", url, parStr);
                //设置header信息
                //指定报文头【Content-type】、【User-Agent】
                httpPost.setHeader("Content-Type", "application/json;charset="+encoding);
    //            httpPost.setHeader("Content-Length", params.length() + "");
    
                //执行请求操作,并拿到结果(同步阻塞)
                CloseableHttpResponse response = httpClient.execute(httpPost);
                //获取结果实体
                HttpEntity entity = response.getEntity();
                if (entity != null) {
                    //按指定编码转换结果实体为String类型
                    String body = EntityUtils.toString(entity, encoding);
                    logger.info(url + "接口返回报文是:/n" + body);
                    return JSON.parseObject(body, LinkedHashMap.class , Feature.OrderedField);
                }
                EntityUtils.consume(entity);
                if(response != null ){
                    //释放链接
                    response.close();
                }
                return null;
            } catch (Exception e) {
                e.printStackTrace();
                return null;
            } finally {
                try {
                    if (null != httpResponse) {
                        httpResponse.close();
                    }
                    logger.info("请求流关闭完成");
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    
      
    }

    注意)=========================================================

    1.JAVA 使用的证书后缀为JKS , 如果不是需要将证书转换为.jks文件

    2.需要在jre中导入证书,而jre(1.8)并不会处理证书链, 必须一个个导入, 如果使用的是中间证书所签发的证书直接导入中间证书即可,

      不必导入根(ROOT)证书 , 如果是根证书直接签发的证书 , 则必须导入根证书

  • 相关阅读:
    HTML颜色表
    grid
    DOM和BO
    注册表
    js 正则表达式
    python学习之路(一)
    python学习之路(三)
    python学习之路(二)
    自己编写的泛型集合类(其实是照着微软的List写的)
    客户端回调服务端无刷新事件
  • 原文地址:https://www.cnblogs.com/cx987514451/p/9792526.html
Copyright © 2020-2023  润新知