以前没做过Https的相关的业务,所以突然来一个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<String,String> 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<ConnectionSocketFactory> 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<ConnectionSocketFactory> registry = registryBuilder.build();
//设置连接管理器
PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager(registry);
//返回生成的CloseableHttpClient
return HttpClientBuilder.create().setConnectionManager(connManager).build();
}
以上我们就可以访问Https单向加密的接口或网址了,比如https://www.baidu.com
Https 双向 API
这个相对单向来说,概念上复杂一些,我也并没有完全搞懂,所以概念上的就不聊太多了。
1 | //首先我们要初始化一个SSLConnectionSocketFactory |
这里我只拿Get请求做了演示,其实Post是一样的,核心操作都在CloseableHttpClient
这个对象实例化的过程发生。
看网上并没有新的解决办法,很多接口都被弃用,甚至是不能用,所以在自己博客里献丑,如果有读者发现有什么不对的话,请点击博客主页Github地址提出Issus,我将不胜感激!