HttpClient单向双向Https请求

Https 是什么

Https是一种认证方式,是在Http协议基础上添加了SSL加密协议,采用https的服务器必须从CA (Certificate Authority)申请一个用于证明服务器用途类型的证书。该证书只有用于对应的服务器的时候,客户端才信任此主机。

Https 长什么样

你可以使用命令行手段生成一个CA,这种本地CA并没有公信力,但我们学习足够用了
基于OpenSSL命令行工具,我们可以很方便的创建CA并签发证书,另外一种方式是从CA认证服务商家处,提供信息,由服务商签发证书。
Https接口方面,还有单向和双向区分,单向证书只需要客户端信任主机,即可正常访问。
双向认证比较麻烦,需要我们本地也生成一个CA,签发证书交给服务端,服务端认证你的证书。并提供他的证书,最终拿到一个jks文件

Https 单向 API

如果想调用Https 单向认证的API,这个好办,我们只需在Java层面,所有证书都选择信任,或加入到java的信任库中
这里我介绍的是Java调用的方式,添加信任库的方法网上很多。

废话不说上代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
/**
    * 单向Https请求入口
    * @return
    */
   public static String HttpsSingletonGetRequest(String requestUrl, Map paramMap) throws Exception{
       StringBuffer resultMsg;
       //封装Client
       CloseableHttpClient httpClient = getSingletonHttpsClient();
       try {
       	//加载URL
           StringBuffer url = new StringBuffer().append(requestUrl);
           //加载参数
           if (!Objects.isNull(paramMap)){
               for (String key : paramMap.keySet()){
                   url.append("&").append(key).append("=").append(paramMap.get(key));
               }
           }

           String realUrl = url.toString().replaceFirst("&", "?");
           HttpGet httpGet = new HttpGet(realUrl);
           httpGet.addHeader("Content-Type", "application/json;encoding=utf-8");
           CloseableHttpResponse response = httpClient.execute(httpGet);
           //发起请求方法
           resultMsg = send(response);
       } finally {
           httpClient.close();
       }
       return resultMsg == null ? null : resultMsg.toString();
   }

/**
    * 发起请求 相信都熟悉HttpClient这个库,我就不废话了
    * @return
    */
private static StringBuffer send(CloseableHttpResponse response) throws IOException {
       try {
           StringBuffer resultMsg = null;
           HttpEntity entity = response.getEntity();
           if (entity != null) {
               resultMsg = new StringBuffer();
               BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(entity.getContent(),"UTF-8"));
               String text;
               while ((text = bufferedReader.readLine()) != null) {
                   resultMsg.append(text);
               }
           }

           EntityUtils.consume(entity);

           if (resultMsg == null){
               throw new RuntimeException("network response error at HttpsClientUtil send()");
           }
           return resultMsg;
       } finally {
           response.close();
       }
   }

/**
    * 核心: 生成Client方法
    * @return
    */
    private static CloseableHttpClient getSingletonHttpsClient() {
    	//首先构建一个注册工厂 用来注册http/https请求
       RegistryBuilder registryBuilder = RegistryBuilder.create();
       ConnectionSocketFactory socketFactory = new PlainConnectionSocketFactory();
       //注册http请求没什么好说的
       registryBuilder.register("http", socketFactory);
       //指定信任密钥存储对象和连接套接字工厂
       try {
       	//实例化一个KeyStore,也就是认证库
           KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
           //信任所有
           TrustStrategy anyTrustStrategy = (x509Certificates, s) -> true;
           //信任所有host
           HostnameVerifier verifier = (s, sslSession) -> true;
           //KeyStore&TrustStrategy加载ssl上下文
           SSLContext sslContext = SSLContexts.custom().loadTrustMaterial(trustStore, anyTrustStrategy).build();
           //此方法是生成一个Socket工场,https请求在真实请求接口前,需提前发起Socket请求验证,参数是ssl上下文以及信任所有host的方法
           LayeredConnectionSocketFactory sslSF = new SSLConnectionSocketFactory(sslContext, verifier);
           //注册Https请求方式
           registryBuilder.register("https", sslSF);
       } catch (KeyStoreException e) {
           throw new RuntimeException(e);
       } catch (KeyManagementException e) {
           throw new RuntimeException(e);
       } catch (NoSuchAlgorithmException e) {
           throw new RuntimeException(e);
       }

       Registry registry = registryBuilder.build();
       //设置连接管理器
       PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager(registry);

       //返回生成的CloseableHttpClient
       return HttpClientBuilder.create().setConnectionManager(connManager).build();
   }

 

以上我们就可以访问Https单向加密的接口或网址了,比如https://www.baidu.com

Https 双向 API

这个相对单向来说,概念上复杂一些,我也并没有完全搞懂,所以概念上的就不聊太多了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
//首先我们要初始化一个SSLConnectionSocketFactory
private static SSLConnectionSocketFactory initConfig() throws Exception {
	KeyStore keyStore = KeyStore.getInstance("jks");
	InputStream in = null;
	try {
		in = new FileInputStream(TRUST_STORE_FILE);
		keyStore.load(in, "bld365".toCharArray());
		SSLContext sslcontext = SSLContexts.custom()
				.loadTrustMaterial(keyStore, new TrustSelfSignedStrategy())
				.loadKeyMaterial(keyStore, "bld365".toCharArray())
				.build();
           HostnameVerifier verifier = (s, sslSession) -> true;
		return new SSLConnectionSocketFactory(
				sslcontext,
				new String[]{"TLSv1", "TLSv1.1", "TLSv1.2"},
				null,
                   verifier
				);
	} catch (Exception e) {
		e.printStackTrace();
		throw new Exception("初始化client keyStore 失败:" + e.getMessage());
	} finally {
		if (null != in) {
			in.close();
		}
	}
}

//然后通过initConfig初始化CloseableHttpClient完成请求
public static String HttpsGetRequest(String requestUrl, Map paramMap) throws Exception{
	StringBuffer resultMsg;
	CloseableHttpClient httpClient = HttpClients.custom().setSSLSocketFactory(initConfig()).build();
	try {
           StringBuffer url = new StringBuffer().append(requestUrl);

           if (!Objects.isNull(paramMap)){
               for (String key : paramMap.keySet()){
                   url.append("&").append(key).append("=").append(paramMap.get(key));
               }
           }

           String realUrl = url.toString().replaceFirst("&", "?");
           HttpGet httpGet = new HttpGet(realUrl);
		CloseableHttpResponse response = httpClient.execute(httpGet);
           resultMsg = send(response);
	} finally {
		httpClient.close();
	}
	return resultMsg == null ? null : resultMsg.toString();
}

//最后调用send方法发送请求
private static StringBuffer send(CloseableHttpResponse response) throws IOException {
       try {
           StringBuffer resultMsg = null;
           HttpEntity entity = response.getEntity();
           if (entity != null) {
               resultMsg = new StringBuffer();
               BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(entity.getContent(),"UTF-8"));
               String text;
               while ((text = bufferedReader.readLine()) != null) {
                   resultMsg.append(text);
               }
           }

           EntityUtils.consume(entity);

           if (resultMsg == null){
               throw new RuntimeException("network response error at HttpsClientUtil send()");
           }
           return resultMsg;
       } finally {
           response.close();
       }
   }

这里我只拿Get请求做了演示,其实Post是一样的,核心操作都在CloseableHttpClient这个对象实例化的过程发生。
看网上并没有新的解决办法,很多接口都被弃用,甚至是不能用,所以在自己博客里献丑,如果有读者发现有什么不对的话,请点击博客主页Github地址提出Issus,我将不胜感激!

CSDN是刚转过来的,更多文章会在我的个人[博客](https://radiancel.github.io)

你可能感兴趣的:(网络相关)