概述
有这样一个场景,出于安全的考虑,某些操作敏感数据的客户端必须通过 VPN 访问服务器端。这种客户端我们姑且称之为代理访问。访问路由示意图:
HTTPS Client <------- Encrypted CONNECT Requests -------> HTTPS Proxy <------- Encrypted CONNECT Requests -------> HTTPS End-Site |
代理地址及端口号作为 Property 参数注入 jvm 进程:https.proxyHost、https.proxyPort。
而大部分客户端不需要 VPN 访问服务器端,只需要通过 HTTPS 直接访问即可。这种客户端我们姑且称之为直连访问。访问路由示意图:
HTTPS Client <------- Encrypted CONNECT Requests -------> HTTPS End-Site |
- 代理配置是以 global 方式提供,也就是说服务器是同一个,所有被分发的客户端启动的时候都有上述 Property 参数
- 这种 VPN 代理跟 LB 代理不同之处在于 proxy 不需要配置 SSL 证书,也就是说 VPN 只负责服务的监听和转发
Solution 1:使用 JVM 原生态 java.net 和 javax.net.ssl 工具包
示意代码:
URL localURL = new URL(urlPath);
URLConnection connection = localURL.openConnection();
HttpURLConnection httpURLConnection = (HttpURLConnection) connection;
if (connection instanceof HttpsURLConnection) {
TrustManager[] tm = {ignoreCertificationTrustManger};
try {
SSLContext sslContext = SSLContext.getInstance("SSL", "SunJSSE");
sslContext.init(null, tm, new java.security.SecureRandom());
SSLSocketFactory ssf = sslContext.getSocketFactory();
((HttpsURLConnection) httpURLConnection).setSSLSocketFactory(ssf);
((HttpsURLConnection) httpURLConnection).setHostnameVerifier(ignoreHostnameVerifier);
} catch (NoSuchAlgorithmException e1) {
logger.logError(e1.getMessage(), e1);
} catch (NoSuchProviderException e1) {
logger.logError(e1.getMessage(), e1);
} catch (KeyManagementException e1) {
logger.logError(e1.getMessage(), e1);
}
}
httpURLConnection.setDoOutput(true);
httpURLConnection.setRequestMethod("POST");
httpURLConnection.setRequestProperty("Content-Type", "application/octet-stream");
httpURLConnection.setRequestProperty("Accept-Encoding", "chunck");
httpURLConnection.setConnectTimeout(3000);
outputStream = httpURLConnection.getOutputStream();
优点:
- 能自动识别 https.proxyHost、https.proxyPort 等 Property
- 能自动识别直连、代理访问环境,然后决定是否用进程内 Property 挂代理访问
缺点:
- 单次访问性能差于 Apache HttpClient 工具包,性能减一
- 连接池化管理差,性能再减一
总之,玩玩或交流学习可以,用于生产环境太儿戏。
Solution 2:使用 Apache HttpClient 工具包的 RequestConfig
示意代码:
HttpHost target = new HttpHost("defonds.net", 443, "https");
HttpHost proxy = new HttpHost("191.168.1.303", 7443, "https");
RequestConfig config = RequestConfig.custom()
.setProxy(proxy)
.build();
HttpGet request = new HttpGet("/");
request.setConfig(config);
CloseableHttpResponse response = httpclient.execute(target, request);
参考自 Apache 官方示例代码:https://hc.apache.org/httpcomponents-client-ga/httpclient/examples/org/apache/http/examples/client/ClientExecuteProxy.java。
直连环境可以,代理环境歇菜。有类似于以下的 SSL 握手问题:
{tls}->https://191.168.1.303:7443->https://defonds.net:443 Connection reset java.net.SocketException: Connection reset at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1367) |
Solution 3:使用 Apache HttpClient 工具包的 HttpRoutePlanner
示意代码:
HttpRoutePlanner routePlanner = new HttpRoutePlanner() {
public HttpRoute determineRoute(
HttpHost target,
HttpRequest request,
HttpContext context) throws HttpException {
return new HttpRoute(target, null, new HttpHost("someproxy", 8080),
"https".equalsIgnoreCase(target.getSchemeName()));
}
};
CloseableHttpClient httpclient = HttpClients.custom()
.setRoutePlanner(routePlanner)
.build();
}
}
参考自 Apache 官方示例代码:http://hc.apache.org/httpcomponents-client-4.5.x/tutorial/html/connmgmt.html#d5e485。
上述代码在代理环境可以,直连环境还需自行适配。
优点:
- 底层做过传输优化,单次性能高于原生态工具包
- 池化管理高效高性能
缺点:
- 不能自动识别 https.proxyHost、https.proxyPort 等 Property
- 代理 / 直连需显式适配
参考资料
- HttpRoutePlanner - How does it work with an HTTPS Proxy
- HttpClient proxy configuration
最后
以上就是正直纸鹤为你收集整理的Apache HttpClient 与 SSL 代理Solution 1:使用 JVM 原生态 java.net 和 javax.net.ssl 工具包Solution 2:使用 Apache HttpClient 工具包的 RequestConfigSolution 3:使用 Apache HttpClient 工具包的 HttpRoutePlanner参考资料的全部内容,希望文章能够帮你解决Apache HttpClient 与 SSL 代理Solution 1:使用 JVM 原生态 java.net 和 javax.net.ssl 工具包Solution 2:使用 Apache HttpClient 工具包的 RequestConfigSolution 3:使用 Apache HttpClient 工具包的 HttpRoutePlanner参考资料所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复