网络环境:
Https客户端
<=============>
代理服务器<==============>
Https服务器
192.168.17.11<-----外网------>
192.168.17.22
10.100.21.10<----内网---->
10.100.21.11注:Http客户端没有默认网关,但可以ping通10.100.21.11
说明:
操作系统:3个主机上的Ubuntu 12.04
Https客户端:使用java(openjdk-6)实现,有一个网络接口。
代理服务器:Apache2.2,有两个网络接口。
Https服务器:Tomcat6,有一个网络接口。
我使用了两种方法通过代理实现httpsurlconnection:
(为方便起见,我没有写出检查serverTrusted和hostnameVerifier问题的ssl处理函数。如有需要,我将更新。)
1.Proxy类
InetSocketAddress proxyInet = new InetSocketAddress("10.100.21.11",80);
Proxy proxy = new Proxy(Proxy.Type.HTTP, proxyInet);
URL httpsUrl = new URL("https://192.168.17.22:8443/test");
HttpsURLConnection httpsCon = (HttpsURLConnection) httpsUrl.openConnection(proxy);
httpsCon.setDoOutput(true);
httpsCon.setDoInput(true);
httpsCon.setRequestMethod("POST");
OutputStream out = httpsCon.getOutputStream();
OutputStreamWriter owriter = new OutputStreamWriter(out);
owriter.write("<request>test</request>");
owriter.flush();
owriter.close();
...
这种方法可行,我观察到数据包的流动也符合我的期望。
HttpClient ---> ProxyServer ---> HttpServer
但是,当我使用 setProperty 方法时:
2.setProperty
System.setProperty("http.proxySet", "true");
System.setProperty("http.proxyHost",10.100.21.11);
System.setProperty("http.proxyPort","80");
URL httpsUrl = new URL("https://192.168.17.22:8443/test");
HttpsURLConnection httpsCon = (HttpsURLConnection)httpsUrl.openConnection();
httpsCon.setDoOutput(true);
httpsCon.setDoInput(true);
httpsCon.setRequestMethod("POST");
OutputStream out = httpsCon.getOutputStream();
OutputStreamWriter owriter = new OutputStreamWriter(out);
owriter.write("<request>test</request>");
owriter.flush();
owriter.close();
...
我遇到了一个 NoRouteToHostException: Network is unreachable
的错误。
这让我感到困惑,因为在 HttpClient 和 ProxyServer 之间没有看到任何数据包传输。
但是 HttpClient 可以 ping 到 ProxyServer(10.100.12.10 ping 10.100.21.11)。
于是我去掉了代理设置(不使用代理):
同样得到了 NoRouteToHostException: Network is unreachable
的错误提示。
我认为这是合理的,因为连外网都没有路线。
我猜测好像是 httpsUrlConnection 内部的 setProperty 方法会检查该 URL 是否能够被访问。
但这很奇怪,第一种方法可以成功。
有什么想法吗?或者第一种和第二种方法之间有什么不同吗?
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
更新
System.setProperty("https.proxyHost",10.100.21.11);
System.setProperty("https.proxyPort","80");
它可以工作,数据包流是我所期望的正确的流。
但是对我来说设置 https.proxyPort=443 是不可行的。
System.setProperty("https.proxyPort","443");
它将抛出以下异常:
java.net.SocketException: Unexpected end of file from server
at sun.net.www.http.HttpClient.parseHTTPHeader(HttpClient.java:770)
....
所以我认为Apache代理也必须进行正确的配置修改。