最近因为项目需要,需要以rest方式和第三方平台交互,由于需要ssl方式连接,所以记录一下:
maven依赖如下:
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.3</version>
</dependency>
这里介绍两种ssl连接方式,一种是ssl信任所有的证书(基本上也就是没有安全性保证),另一种是ssl的正常使用(需要证书认证的)
首先是一个工具类
2019/4/3补充,前段时间,部署到生产环境后发生了一点问题,观察服务器日志(websphere)发现是报告线程挂起,通过查询google,发现是因为建立http连接后,没有关闭资源 ,造成资源耗尽,今天重新编辑此文
主要 增加了资源池对象 HttpClientConnectionManager
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import javax.net.ssl.X509TrustManager;
public class HttpsTrustManager implements X509TrustManager {
@Override
public void checkClientTrusted(X509Certificate[] arg0, String arg1)
throws CertificateException {
// TODO Auto-generated method stub
}
@Override
public void checkServerTrusted(X509Certificate[] arg0, String arg1)
throws CertificateException {
// TODO Auto-generated method stub
}
@Override
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[]{};
}
}
正常SSL方式(需要证书)的工厂类
package com.haitaiinc.orionmonitor.util;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.util.Map;
import javax.net.ssl.SSLContext;
import org.apache.http.conn.HttpClientConnectionManager;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLContexts;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
/**
* 构建httpclient的
* @author Think
*
*/
public class HttpClientFactory {
private static CloseableHttpClient client;
//连接池
private static HttpClientConnectionManager poolingConnManager = new PoolingHttpClientConnectionManager();
/**
* 获取需要安全认证的httpClient的实例
* @Title: getHttpsClient
* @Description: TODO
* @Author: Think
* @Date :Jan 16, 2019
* @return: HttpClient
*/
public static CloseableHttpClient getHttpsClient() throws Exception {
if (client != null) {
return client;
}
SSLContext sslcontext = getSSLContext();
SSLConnectionSocketFactory factory = new SSLConnectionSocketFactory(sslcontext,
SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
client = HttpClients.custom().setConnectionManager(poolingConnManager).setSSLSocketFactory(factory).build();
return client;
}
private static SSLContext getSSLContext() throws KeyStoreException,
NoSuchAlgorithmException, CertificateException, IOException, KeyManagementException {
KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
Map<String, String> map = ParseSSLUtil.getInterfaceConfig();
String keyLocation = map.get("keystore");
FileInputStream instream = new FileInputStream(new File(keyLocation));
try {
trustStore.load(instream, "changeit".toCharArray());
} finally {
instream.close();
}
return SSLContexts.custom()
.loadTrustMaterial(trustStore)
.build();
}
public static void releaseInstance() {
client = null;
}
}
不安全的SSL方式的工厂类
package com.haitaiinc.orionmonitor.util;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.cert.CertificateException;
import javax.net.ssl.SSLContext;
import javax.net.ssl.X509TrustManager;
import org.apache.http.client.HttpClient;
import org.apache.http.conn.HttpClientConnectionManager;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLContexts;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
public class HttpClientFactoryWithNoSSL {
private static CloseableHttpClient client;
//连接池
private static HttpClientConnectionManager poolingConnManager = new PoolingHttpClientConnectionManager();
/**
* 获取不需要ssl认证的httpClient实例
* @Title: getHttpsClientWithNoCert
* @Description: TODO
* @Author: Think
* @Date :Jan 16, 2019
* @return: HttpClient
*/
public static HttpClient getHttpsClient() throws Exception {
if (client != null) {
return client;
}
SSLContext sslcontext = SSLContexts.custom().useSSL().build();
sslcontext.init(null, new X509TrustManager[]{new HttpsTrustManager()}, new SecureRandom());
SSLConnectionSocketFactory factory = new SSLConnectionSocketFactory(sslcontext,
SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
client = HttpClients.custom().setConnectionManager(poolingConnManager).setSSLSocketFactory(factory).build();
return client;
}
public static void releaseInstance() {
client = null;
}
}
使用样例:
//获取httpclient客户端
CloseableHttpClient httpsClient = HttpClientFactory.getHttpsClient();
//因为需要认证就是需要将{用户名:密码}变成字节数组并base64编码
byte[] admin= ParseSSLUtil.getUserTokenString().getBytes();
String encoding = ParseSSLUtil.encodeBase64(admin);
//内存使用情况
HttpGet httpGet = new HttpGet(config.get("url").concat("/api/statistics/memoryusage"));
httpGet.addHeader("Content-Type", "application/json");
httpGet.setHeader("Authorization", "Basic " + encoding);
String mem = "";
CloseableHttpResponse responseMem = null;
CloseableHttpResponse responseCPU = null;
CloseableHttpResponse responseDisk = null;
try {
responseMem = httpsClient.execute(httpGet);
if(responseMem.getStatusLine().getStatusCode()!=HttpStatus.SC_OK){
mem = "0";
}else{
HttpEntity entity = responseMem.getEntity();
if(entity != null){
mem = EntityUtils.toString(entity,"UTF-8");
}
EntityUtils.consume(entity);//要消耗消息实体,这是必须步骤
}
} catch (Exception e1) {
e1.printStackTrace();
mem = "0";
}finally{
responseMem.close();//尝试关闭资源,将socket连接返回给资源池
}