1. 不使用证书
1.1 客户端
1.1.1 该方式不校验证书和域名,与普通的访问http无明显差别
public void testPlainHttps() {
URL reqURL;
try {
reqURL = new URL("https://www.oracle.com/sun/index.html");
// 创建URL对象
HttpsURLConnection httpsConn = (HttpsURLConnection) reqURL.openConnection();
/*
* 下面这段代码实现向Web页面发送数据,实现与网页的交互访问 httpsConn.setDoOutput(true);
* OutputStreamWriter out = new
* OutputStreamWriter(huc.getOutputStream(), "8859_1");
* out.write("……" );
* out.flush();
* out.close();
*/
// 取得该连接的输入流,以读取响应内容
InputStreamReader insr = new InputStreamReader(httpsConn.getInputStream());
// 读取服务器的响应内容并显示
int respInt = insr.read();
while (respInt != -1) {
System.out.print((char) respInt);
respInt = insr.read();
}
} catch (Exception e) {
e.printStackTrace();
}
}
1.1.2 忽略证书和域名校验,实现方式是构造一个信任证书管理器(不做校验)
public String sendBankServer(String postData, String reqUrl) throws Exception {
LOGGER.info("\n请求银行URL:" + reqUrl + "\n发送银行内容:" + postData);
CloseableHttpClient httpClient = getIgnoredCertHttpClient();
StringEntity stringEntity = new StringEntity(postData, "GBK");
stringEntity.setContentEncoding("GBK");
stringEntity.setContentType("text/xml; charset=GBK");
HttpPost httpPost = new HttpPost(reqUrl);
httpPost.setHeader("Content-Type", "text/xml; charset=GBK");
httpPost.setHeader("Host", BANK_HOST);
httpPost.setEntity(stringEntity);
String responseBody = "";
try {
// 执行请求操作,并拿到结果(同步阻塞)
CloseableHttpResponse response = httpClient.execute(httpPost);
// 获取结果实体
HttpEntity httpEntity = response.getEntity();
if (httpEntity != null) {
// 按指定编码转换结果实体为String类型
responseBody = EntityUtils.toString(httpEntity, "GBK");
}
// 释放httpEntity占用的所有资源,实质是释放底层的流并将连接归还连接池
EntityUtils.consume(httpEntity);
// 释放链接
response.close();
} finally {
httpClient.close();
}
LOGGER.info("收到银行回复:" + responseBody);
return responseBody;
}
public CloseableHttpClient getIgnoredCertHttpClient() throws KeyManagementException, NoSuchAlgorithmException {
// 实现一个X509TrustManager接口,信任证书用于绕过验证,不用修改里面的方法
X509TrustManager trustManager = new X509TrustManager() {
@Override
public void checkClientTrusted(java.security.cert.X509Certificate[] paramArrayOfX509Certificate, String paramString) throws CertificateException {}
@Override
public void checkServerTrusted(java.security.cert.X509Certificate[] paramArrayOfX509Certificate, String paramString) throws CertificateException {}
@Override
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return null;
}
};
SSLContext sslContext = SSLContext.getInstance("SSLv3");
// 采用绕过验证的方式处理https请求
sslContext.init(null, new TrustManager[] { trustManager }, null);
// 设置协议http和https对应的处理socket链接工厂的对象
Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory> create()
.register("http", PlainConnectionSocketFactory.INSTANCE)
// 不校验主机名
.register("https", new SSLConnectionSocketFactory(sslContext, new AllowAllHostnameVerifier()))
.build();
//创建http连接池管理器
PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry);
// 请求参数设置
RequestConfig requestConfig = RequestConfig.custom()
// 从连接池中获取连接的超时时间
.setConnectionRequestTimeout(MAX_TIMEOUT)
// 与服务器连接超时时间:httpclient会创建一个异步线程用以创建socket连接,此处设置该socket的连接超时时间
.setConnectTimeout(MAX_TIMEOUT)
// socket读取数据时阻塞链路的超时时间,即从服务器获取响应数据的超时时间
.setSocketTimeout(MAX_TIMEOUT)
// 在提交请求之前测试连接是否可用The stale connection check can cause up to 30 millisecond overhead per request
//.setStaleConnectionCheckEnabled(true)
// 不做认证
.setAuthenticationEnabled(false)
.build();
// 创建自定义的httpclient对象
CloseableHttpClient httpClient = HttpClients.custom().setConnectionManager(connManager)
.setDefaultRequestConfig(requestConfig)
.build();
return httpClient;
}
1.1.3 忽略证书和域名校验
package com.eplusing.communication;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.URL;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.KeyManager;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import org.junit.Test;
public class HttpsUtil {
public static void main(String[] args) throws IOException {
String uri = "https://f.hiphotos.baidu.com/image/pic/item/960a304e251f95cacc952852c5177f3e660952f5.jpg";
byte[] bytes = HttpsUtil.doGet(uri);
FileOutputStream fos = new FileOutputStream("file/金丝皇菊.jpg");
fos.write(bytes);
fos.close();
System.out.println("done!");
}
private static final class DefaultTrustManager implements 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;
}
}
private static HttpsURLConnection getHttpsURLConnection(String uri, String method) throws IOException {
SSLContext ctx = null;
try {
ctx = SSLContext.getInstance("TLS");
ctx.init(new KeyManager[0], new TrustManager[] { new DefaultTrustManager() }, new SecureRandom());
} catch (KeyManagementException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
SSLSocketFactory ssf = ctx.getSocketFactory();
URL url = new URL(uri);
HttpsURLConnection httpsConn = (HttpsURLConnection) url.openConnection();
httpsConn.setSSLSocketFactory(ssf);
httpsConn.setHostnameVerifier(new HostnameVerifier() {
@Override
public boolean verify(String arg0, SSLSession arg1) {
return true;
}
});
httpsConn.setRequestMethod(method);
httpsConn.setDoInput(true);
httpsConn.setDoOutput(true);
return httpsConn;
}
private static HttpsURLConnection getHttpsURLConnection2(String uri, String method) {
//创建SSLContext对象,并使用我们指定的信任管理器初始化
// 创建URL对象
HttpsURLConnection httpsConn = null;
try {
TrustManager[] tm = {new DefaultTrustManager ()};
SSLContext sslContext = SSLContext.getInstance("SSL","SunJSSE");
sslContext.init(null, tm, new java.security.SecureRandom());
//从上述SSLContext对象中得到SSLSocketFactory对象
SSLSocketFactory ssf = sslContext.getSocketFactory();
//创建HttpsURLConnection对象,并设置其SSLSocketFactory对象
URL reqURL = new URL("https://www.oracle.com/sun/index.html");
httpsConn = (HttpsURLConnection) reqURL.openConnection();
httpsConn.setSSLSocketFactory(ssf);
httpsConn.setHostnameVerifier(new HostnameVerifier() {
@Override
public boolean verify(String arg0, SSLSession arg1) {
return true;
}
});
httpsConn.setRequestMethod(method);
httpsConn.setDoInput(true);
httpsConn.setDoOutput(true);
} catch (Exception e) {
e.printStackTrace();
}
return httpsConn;
}
private static byte[] getBytesFromStream(InputStream is) throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] kb = new byte[1024];
int len;
while ((len = is.read(kb)) != -1) {
baos.write(kb, 0, len);
}
byte[] bytes = baos.toByteArray();
baos.close();
is.close();
return bytes;
}
private static void setBytesToStream(OutputStream os, byte[] bytes) throws IOException {
ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
byte[] kb = new byte[1024];
int len;
while ((len = bais.read(kb)) != -1) {
os.write(kb, 0, len);
}
os.flush();
os.close();
bais.close();
}
public static byte[] doGet(String uri) throws IOException {
HttpsURLConnection httpsConn = getHttpsURLConnection(uri, "GET");
return getBytesFromStream(httpsConn.getInputStream());
}
public static byte[] doPost(String uri, String data) throws IOException {
HttpsURLConnection httpsConn = getHttpsURLConnection(uri, "POST");
setBytesToStream(httpsConn.getOutputStream(), data.getBytes());
return getBytesFromStream(httpsConn.getInputStream());
}
}
1.2 服务端
2. 使用证书
public CloseableHttpClient getHttpClient(String certFilePath,String keyStoryPwd) {
FileInputStream instream = null;
CloseableHttpClient httpclient = null;
try {
// 指定读取证书格式为PKCS12
KeyStore keyStore = KeyStore.getInstance("PKCS12");
// 读取本机存放的PKCS12证书文件
instream = new FileInputStream(new File(certFilePath));
// 指定PKCS12的密码(商户ID)
keyStore.load(instream, keyStoryPwd.toCharArray());
SSLContext sslcontext = SSLContexts.custom().loadKeyMaterial(keyStore, keyStoryPwd.toCharArray()).build();
// 指定TLS版本
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslcontext,new String[] { "TLSv1" },null,
SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
// 设置httpclient的SSLSocketFactory
httpclient = HttpClients.custom().setSSLSocketFactory(sslsf).build();
} catch (KeyStoreException e) {
LOGGER.error("私钥文件异常", e);
} catch (FileNotFoundException e) {
LOGGER.error("证书文件未找到", e);
}catch (NoSuchAlgorithmException e) {
LOGGER.error("算法异常", e);
} catch (CertificateException e) {
LOGGER.error("证书异常", e);
} catch (IOException e) {
LOGGER.error("读取证书文件异常", e);
} catch (KeyManagementException e) {
LOGGER.error("KeyManagementException异常", e);
} catch (UnrecoverableKeyException e) {
LOGGER.error("UnrecoverableKeyException异常", e);
}finally{
if(instream !=null){
try {
instream.close();
} catch (IOException e) {
LOGGER.error("inputStream close IOException:" + e.getMessage());
}
}
}
return httpclient;
}
protected String postRequest(String urlAddr, String reqXml) throws Exception {
String responseXML = null;
//import httpclient-4.3.6.jar
CloseableHttpResponse response = null;
String keyStoryPwd = "证书密钥";
String certFilePath = "证书地址";
CloseableHttpClient httpclient = getHttpClient(certFilePath,keyStoryPwd);
try {
HttpPost httppost = new HttpPost(urlAddr);
StringEntity pentity = new StringEntity(reqXml, Charset.forName("UTF-8"));
pentity.setContentEncoding("UTF-8");
pentity.setContentType("text/xml");
httppost.setEntity(pentity);
response = httpclient.execute(httppost);
HttpEntity entity = response.getEntity();
if (entity != null) {
//import httpcore-4.3.3.jar EntityUtils
byte[] buff = EntityUtils.toByteArray(entity);
responseXML = new String(buff, "UTF-8");
}
LOGGER.info("receive:" + responseXML);
return responseXML;
} catch (IOException e) {
LOGGER.error("读返回信息失败" + e.getMessage());
} finally {
try {
response.close();
} catch (IOException e) {
LOGGER.error("response close IOException:" + e.getMessage());
}
try {
httpclient.close();
} catch (IOException e) {
LOGGER.error("httpclient close IOException:" + e.getMessage());
}
}
return null;
}