https通信实现方式

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/cpp1781089410/article/details/81319558

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;
    }

猜你喜欢

转载自blog.csdn.net/cpp1781089410/article/details/81319558