如何为单个 HttpsURLConnections 设置 https.proxyHost 和 https.proxyPort?

Posted

技术标签:

【中文标题】如何为单个 HttpsURLConnections 设置 https.proxyHost 和 https.proxyPort?【英文标题】:How can I set https.proxyHost and https.proxyPort for individual HttpsURLConnections? 【发布时间】:2022-01-11 06:22:56 【问题描述】:

我正在尝试通过代理发出 HTTPS 请求。这是我到目前为止所得到的,基于来自this question 的代码:

try 
    HttpsURLConnection connection = (HttpsURLConnection) new URL("https://proxylist.geonode.com/api/proxy-list?limit=1&page=1&sort_by=speed&sort_type=asc&protocols=https").openConnection();
    connection.setRequestMethod("GET");
    connection.setDoInput(true);
    connection.setDoOutput(true);
    connection.setRequestProperty("user-agent", "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (Khtml, like Gecko) Chrome/96.0.4664.45 Safari/537.36");
    connection.setConnectTimeout(30000);
    connection.connect();
    
    BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
    String rawJSON = reader.readLine();
    if(rawJSON == null) throw new IOException("No data");

    JSONObject data = new JSONObject(rawJSON).getJSONArray("data").getJSONObject(0);

    String ipAddress = data.getString("ip"), port = data.getString("port");

    System.setProperty("https.proxyHost", ipAddress);
    System.setProperty("https.proxyPort", port);

    SSLContext sslContext = SSLContext.getInstance("SSL");

    // set up a TrustManager that trusts everything
    sslContext.init(null, new TrustManager[]  new X509TrustManager() 
        public X509Certificate[] getAcceptedIssuers()  return null; 
        public void checkClientTrusted(X509Certificate[] certs, String authType) 
        public void checkServerTrusted(X509Certificate[] certs, String authType) 
     , new SecureRandom());

    HttpsURLConnection.setDefaultSSLSocketFactory(sslContext.getSocketFactory());

    HttpsURLConnection.setDefaultHostnameVerifier((arg0, arg1) -> true);

    HttpsURLConnection testConnection = (HttpsURLConnection) new URL("https://example.com").openConnection();
    testConnection.connect();

    StringBuilder result = new StringBuilder();
    String line;
    try(BufferedReader reader2 = new BufferedReader(new InputStreamReader(testConnection.getInputStream()))) 
        while ((line = reader2.readLine()) != null) result.append(line);
    

    System.out.println(result);
 catch(Exception e) 
    e.printStackTrace();

代码有效,但有问题。我的应用程序 (https://encyclosearch.org) 是多线程的,我需要通过代理发出一些请求,还有一些直接发出请求。由于系统属性是全局的,如果我使用System.setProperty 设置https.proxyHosthttps.proxyPort,一些不应该通过代理的请求将通过代理。

我可以像这样使用java.net.Proxy

Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(ipAddress, Integer.parseInt(port)));

HttpsURLConnection testConnection = (HttpsURLConnection) new URL("http://example.com").openConnection(proxy);

但这仅适用于 HTTP 代理,不适用于 HTTPS 代理,因此我无法发出 HTTPS 请求。没有Proxy.Type.HTTPS

任何帮助将不胜感激。提前致谢。

【问题讨论】:

【参考方案1】:

在@Bashi 的帮助下,我想通了。对于直接连接,我使用了:

url.openConnection(Proxy.NO_PROXY);

这也适用于Jsoup:

Document document = Jsoup.connect("https://example.com").proxy(Proxy.NO_PROXY).get();

来自https://docs.oracle.com/javase/8/docs/technotes/guides/net/proxies.html的解释:

现在,这可以保证您可以通过绕过任何其他代理设置的直接连接来检索此特定 URL,这很方便。

【讨论】:

【参考方案2】:

如果您选择哪些连接通过代理,哪些不通过目标 url,那么您可以使用属性 http.nonProxyHosts。如文档所述,此属性用于 http 和 https:

对于“非代理主机”列表,HTTPS 协议处理程序将使用与 http 处理程序相同的内容(即 http.nonProxyHosts)。

您可以通过添加由 | 分隔的 url 模式来设置属性值例如:

System.setProperty("http.nonProxyHosts", ”localhost|host.example.com”)

您还可以使用 ProxySelector 类来选择通过代理的连接。更多信息(有点旧): https://docs.oracle.com/javase/8/docs/technotes/guides/net/proxies.html

至于没有 Proxy.Type.HTTPS,这是因为代理通常不是最终目的地,因此安全连接将与最终目的地而不是代理本身。有通过代理的 SSL 隧道之类的东西,但我不太了解它。

【讨论】:

感谢您的回答!这篇文章很有帮助。

以上是关于如何为单个 HttpsURLConnections 设置 https.proxyHost 和 https.proxyPort?的主要内容,如果未能解决你的问题,请参考以下文章

如何为单个雄辩的对象急切加载关系?

如何为单个联系人创建 .vcf 文件?

如何为 QTableView 中的单个单元格设置委托?

如何为 UISplitviewController 导航栏图像使用单个图像?

如何为单个剑道网格列设置最大宽度属性?

如何为每组线添加单个图例标签