概述
本文主要介绍JAVA实现https接口调用包括忽略本地证书方式和加载本地证书方式两种.
第一种:忽略本地证书方式
忽略本地证书方式就是服务器不对客户端证书做校验的网站比如 www.baidu.com,
和其他https网站不一样,其他网站需要客户端本地拥有证书文件,在客户端调用的时候加载.
1.编写HttpClientUtil工具类
import org.apache.commons.lang.StringUtils;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.message.BasicHeader;
import org.apache.http.params.CoreConnectionPNames;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
*
* @Description: 利用HttpClient进行post请求的工具类
* @author: jackromer
* @version: 1.0, Jan 25, 2019
*/
@SuppressWarnings("deprecation")
public class HttpClientUtil {
public static final Logger logger = LoggerFactory.getLogger(HttpClientUtil.class);
/**
* 发送post消息
* @Description:
* @param url
* @param jsonstr
* @param charset
* @return
*/
public static void doPost(String url,String jsonstr,String charset){
logger.info("POST MESSAGE:" + jsonstr);
HttpClient httpClient = null;
HttpPost httpPost = null;
String result = null;
try {
httpClient = new SSLClient();
httpClient.getParams().setParameter(CoreConnectionPNames.CONNECTION_TIMEOUT, 30000);
httpPost = new HttpPost(url);
httpPost.addHeader("Content-Type", "application/json");
StringEntity se = new StringEntity(jsonstr);
se.setContentType("text/json");
se.setContentEncoding(new BasicHeader("Content-Type", "application/json"));
httpPost.setEntity(se);
HttpResponse response = httpClient.execute(httpPost);
if (response != null){
HttpEntity resEntity = response.getEntity();
if (resEntity != null) {
result = EntityUtils.toString(resEntity,charset);
}
}
} catch(Exception ex){
ex.printStackTrace();
logger.error("POST MSG ERROR.", ex);
}
if (!StringUtils.isEmpty(result)) {
logger.info("POST RESULT:" + result);
} else {
logger.error("POST RESULT IS NULL.");
}
}
}
2.编写https的SSLClient类
/**
* @Description: 用于进行Https请求的HttpClient
* @author: jackromer
* @version: 1.0, Jan 24, 2019
*/
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import org.apache.http.conn.ClientConnectionManager;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.impl.client.DefaultHttpClient;
@SuppressWarnings("deprecation")
public class SSLClient extends DefaultHttpClient{
public SSLClient() throws Exception{
super();
SSLContext ctx = SSLContext.getInstance("TLS");
X509TrustManager tm = new X509TrustManager() {
@Override
public void checkClientTrusted(X509Certificate[] chain,
String authType) throws CertificateException {
}
@Override
public void checkServerTrusted(X509Certificate[] chain,
String authType) throws CertificateException {
}
@Override
public X509Certificate[] getAcceptedIssuers() {
return null;
}
};
ctx.init(null, new TrustManager[]{tm}, null);
HostnameVerifier ignoreHostnameVerifier = new HostnameVerifier() {
public boolean verify(String s, SSLSession sslsession) {
System.out.println("WARNING: Hostname is not matched for cert.");//忽略本地证书文件校验
return true;
}
};
HttpsURLConnection.setDefaultHostnameVerifier(ignoreHostnameVerifier);
HttpsURLConnection.setDefaultSSLSocketFactory(ctx.getSocketFactory());
SSLSocketFactory ssf = new SSLSocketFactory(ctx,SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
ClientConnectionManager ccm = this.getConnectionManager();
SchemeRegistry sr = ccm.getSchemeRegistry();
sr.register(new Scheme("https", 443, ssf));
}
}
3. 创建POST请求测试
public static void main(String[] args) {
String httpsUrl = "https://ip:post/restName";
String postJson = "{\"test\":\"hello\"}";
HttpClientUtil.doPost(httpsUrl, postJson, "utf-8");
}
第二种:加载本地证书和key的方式
1.创建httpsClient
/**
* @Description:
* @author: zhouqiang
* @version: 1.0, Jan 25, 2019
*/
@SuppressWarnings("unchecked")
public class HttpsClient {
private static String CONTENT_LENGTH = "Content-Length";
private CloseableHttpClient closeableHttpClient;
/**
* 初始化证书
*/
public void initSSLConfig(){
try {
//加载证书
InputStream selfInputStream = HttpsClient.class.getClassLoader().getResourceAsStream(GatewayNbConstants.PKCS12_PATH);//PKCS12文件地址
InputStream caInputStream = HttpsClient.class.getClassLoader().getResourceAsStream(GatewayNbConstants.JKS_PATH);//JKS证书文件地址
if (selfInputStream == null || caInputStream == null){
return;
}
KeyStore pksKeyStore = KeyStore.getInstance("pkcs12");
pksKeyStore.load(selfInputStream, GatewayNbConstants.PKCS12_PASSWORD.toCharArray());
selfInputStream.close();
KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance("sunx509");
keyManagerFactory.init(pksKeyStore, GatewayNbConstants.PKCS12_PASSWORD.toCharArray());//PKCS12的密码
KeyStore jksKeyStore = KeyStore.getInstance("jks");
jksKeyStore.load(caInputStream, GatewayNbConstants.JKS_PASSWORD.toCharArray());//JKS的密码
caInputStream.close();
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance("sunx509");
trustManagerFactory.init(jksKeyStore);
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(keyManagerFactory.getKeyManagers(), trustManagerFactory.getTrustManagers(), new SecureRandom());
SSLConnectionSocketFactory ssf = new SSLConnectionSocketFactory(sslContext, new HostnameVerifier() {
@Override
public boolean verify(String s, SSLSession sslSession) {
return true;
}
});
closeableHttpClient = HttpClients.custom().setSSLSocketFactory(ssf).build();
}catch (Exception en){
en.printStackTrace();
}
}
/**
* @Description: post请求
* @param url https路径
* @param headerMap 请求头信息
* @param params 请求参数
* @param contentType 请求类型
* @return CloseableHttpResponse
*/
public CloseableHttpResponse post(String url, Map<String, String> headerMap, String params, ContentType contentType) throws IOException{
HttpPost request = new HttpPost(url);
addRequestHeader(request, headerMap);
request.setEntity(new StringEntity(params, contentType));
return closeableHttpClient.execute(request);
}
/**
* @Description: post请求
* @param url https路径
* @param params 请求参数
* @return CloseableHttpResponse
*/
@SuppressWarnings("rawtypes")
public CloseableHttpResponse post(String url, List params) throws IOException{
HttpPost request = new HttpPost(url);
request.setEntity(new UrlEncodedFormEntity(params, "utf-8"));
return closeableHttpClient.execute(request);
}
/**
* 添加请求头参数
* @Description:
* @param request
* @param headerMap
*/
private void addRequestHeader(HttpUriRequest request, Map<String, String> headerMap) {
if (headerMap == null) {
return;
}
for (String headerName : headerMap.keySet()) {
if (CONTENT_LENGTH.equalsIgnoreCase(headerName)) {
continue;
}
request.addHeader(headerName, headerMap.get(headerName));
}
}
}
2.加载p12文件
如果使用的是springboot,则需要在application.properties文件中添加如下配置,这是为了让springboot启动时自动加载这些参数和文件到springboot context中去.具体配置可参照springboot官网对HTTPS SSL的支持.
server.ssl.key-store-type=PKCS12
server.ssl.key-store=classpath:server.p12 #server.p12文件最好放在更目录中以保证springboot加载正确.
server.ssl.key-store-password=yourpassword
3.编写TestService发送post请求
import java.io.IOException;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import org.apache.http.HttpEntity;
import org.apache.http.NameValuePair;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.entity.ContentType;
import org.apache.http.message.BasicNameValuePair;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.sefon.gateway.NbHuaweiHttpsModule.common.HttpsClient;
import com.sefon.gateway.NbHuaweiHttpsModule.utils.StreamUtil;
/**
* @Description:
* @author: jackromer
* @version: 1.0, Jan 25, 2019
*/
@Component
@SuppressWarnings("unchecked")
public class TestService {
private static final Logger logger = LoggerFactory.getLogger(TestService.class);
private HttpsClient httpsClient;
public TestService(){
this.httpsClient = new HttpsClient();
this.httpsClient.initSSLConfig();
}
/**
* 用list参数请求
* @Description:
*/
@SuppressWarnings("rawtypes")
public void postList(){
try {
String postUrl = null;//your post url
List<NameValuePair> postParas = new LinkedList();
postParas.add(new BasicNameValuePair("name1","value1"));
postParas.add(new BasicNameValuePair("name2","value2"));
CloseableHttpResponse response = httpsClient.post(postUrl, postParas);
String responseBody = getResponseContent(response);
logger.info("post result", responseBody);
} catch (Exception en) {
logger.error("post error", en);
}
}
/**
* 用json或其他类型请求
* @Description:
* @param postJson
*/
@SuppressWarnings("rawtypes")
@Async
public void postJsonStr(ObjectNode postJson){
try {
//封装应用命令下发的头信息
String postUrl = null;//your post url
Map headers = null;//your header
CloseableHttpResponse httpResponse = httpsClient.post(postUrl, headers, postJson.toString(), ContentType.APPLICATION_JSON);
int statusCode = httpResponse.getStatusLine().getStatusCode();
if (statusCode == HttpStatus.CREATED.value()){
logger.info("post success");
}
} catch (Exception en){
en.printStackTrace();
}
}
/**
* 获取返回数据
* @Description:
* @param closeableHttpResponse
* @return
* @throws IOException
*/
private String getResponseContent(CloseableHttpResponse closeableHttpResponse) throws IOException {
String content = null;
if (closeableHttpResponse != null){
try {
HttpEntity httpEntity = closeableHttpResponse.getEntity();
if (httpEntity != null && httpEntity.isStreaming()){
String encoding = httpEntity.getContentEncoding() != null ? httpEntity.getContentEncoding().getValue() : null;
content = StreamUtil.inputStream2String(httpEntity.getContent(), encoding);
}
} finally {
closeableHttpResponse.close();
}
}
return content;
}
}
4. 测试TestService发送请求
import java.io.IOException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import com.sefon.gateway.NbHuaweiHttpsModule.service.TestService;
/**
* @Description:
* @author: jackromer
* @version: 1.0, Jan 25, 2019
*/
@Component
public class TestPost {
@Autowired
private TestService testService;
/**
* 通过TestService 调用https接口
* @Description:
*/
public void post() throws IOException{
try {
//testService.postList();
testService.postJsonStr(null);//your json Str
} catch (Exception e){
e.printStackTrace();
}
}
}
总结
以上就是JAVA调用https的两种方式,第一种不需要验证本地证书,第二种则为混合加密方式,需要验证本地证书和key是否正确。