springboot2.X集成HttpClient 发送HTTPS 请求
Posted 陈先生的小板凳
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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)证书 , 如果是根证书直接签发的证书 , 则必须导入根证书
以上是关于springboot2.X集成HttpClient 发送HTTPS 请求的主要内容,如果未能解决你的问题,请参考以下文章
搞定全局ID生成器:SpringBoot2.x 集成百度 uidgenerator
又一神操作,SpringBoot2.x 集成百度 uidgenerator搞定全局ID