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

How can I set https.proxyHost and https.proxyPort for individual HttpsURLConnections?

我正在尝试通过代理发出 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.

如有任何帮助,我们将不胜感激。提前致谢。

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

for the "non proxy hosts" list, the HTTPS protocol handler will use the same as the http handler (i.e. http.nonProxyHosts).

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

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

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

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

在@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的解释:

Now, this guarantees you that this specific URL will be retrieved though a direct connection bypassing any other proxy settings, which can be convenient.