如何通过setProperty通过代理使用HttpsURLConnection?

时间:2013-04-10 13:21:56

标签: java networking proxy outputstream httpsurlconnection

网络环境:

  

Https客户端< =============>代理服务器< ==============> Https服务器
  192.168.17.11< ----- ------外联网> 192.168.17.22
  10.100.21.10< ---- -----内联网> 10.100.21.11

     

ps:没有默认网关的Http客户端,但它可以ping到10.100.21.11

描述:

  操作系统:3台主机上的Ubuntu 12.04   Https Client:用java实现(openjdk-6)。有一个网络接口   代理服务器:Apache2.2。有两个网络接口   Https Server:Tomcat6.Have one network-interface。

我使用两种方法通过代理实现 httpsurlconnection
(为方便起见,我没有写下关于用于检查 serverTrusted hostnameVerifier 问题的ssl句柄功能。如果需要我会更新。)

1.Proxy class

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 ---&gt; ProxyServer ---&gt;的HttpServer

但是当我使用set Property方法时:

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 我认为这是合理的。因为没有外联网的路线。

我想似乎 setProperty 方法 httpsUrlConnection 的内部函数将检查此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 Proxy也必须修改为正确的配置。

3 个答案:

答案 0 :(得分:15)

您的网址连接是https,而您只设置了http代理。

尝试设置https代理。

//System.setProperty("https.proxySet", "true"); 
 System.setProperty("https.proxyHost",10.100.21.11);
 System.setProperty("https.proxyPort","443");

修改 @EJP是对的。没有https.proxySet ..我复制了您的原始问题并包含在答案中。

答案 1 :(得分:9)

您需要为其创建一个Proxy对象。创建一个如下:

Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(proxyServer, Integer.parseInt(proxyPort)));

现在使用此代理创建HttpURLConnection对象。

HttpURLConnection connection = (HttpURLConnection) new URL(url).openConnection(proxy);

如果必须设置代理的凭据,请设置Proxy-Authorization请求属性:

String uname_pwd = proxyUsername + ":" + proxyPassword
String authString = "Basic " + new sun.misc.BASE64Encoder().encode(uname_pwd.getBytes())
connection.setRequestProperty("Proxy-Authorization", authString);

最后,你连接:

connection.connect();

答案 2 :(得分:0)

谢谢@divinedragon!

kotlin上的代码相同:

 fun testProxy(login: String, pass: String, proxyData: ProxyData): String {
    val url = URL("http://api.ipify.org")
    val proxy = Proxy(Proxy.Type.HTTP, InetSocketAddress(proxyData.ip, proxyData.port))
    val connection = url.openConnection(proxy) as HttpURLConnection

    val loginPass = "$login:$pass"
    val encodedLoginPass = Base64.getEncoder().encodeToString(loginPass.toByteArray())
    val authString = "Basic $encodedLoginPass"
    connection.setRequestProperty("Proxy-Authorization", authString);
    with(connection) {
        requestMethod = "GET"  // optional default is GET
        connectTimeout = 2000
        readTimeout = 2000
        return inputStream.bufferedReader().readText()
    }
}