1. 程式人生 > >springboot2.X集成HttpClient 發送HTTPS 請求

springboot2.X集成HttpClient 發送HTTPS 請求

keys fin 去掉 ntb key 資源 ttpClient 路徑 rep

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)證書 , 如果是根證書直接簽發的證書 , 則必須導入根證書

技術分享圖片

springboot2.X集成HttpClient 發送HTTPS 請求