如何将HttpClientBuilder与Http代理一起使用?

2022-09-03 18:36:23

我正在尝试为我发出的请求设置代理,如下所示:HttpClientBuilder

        CredentialsProvider credsProvider = new BasicCredentialsProvider();
        UsernamePasswordCredentials usernamePasswordCredentials = new UsernamePasswordCredentials(proxyUser, proxyPassword);
        credsProvider.setCredentials(new AuthScope(proxyHost, proxyPort), usernamePasswordCredentials);

        builder.useSystemProperties();
        builder.setProxy(new HttpHost(proxyHost, proxyPort));
        builder.setDefaultCredentialsProvider(credsProvider);
        builder.setProxyAuthenticationStrategy(new ProxyAuthenticationStrategy());

其中生成器是:

    HttpClientBuilder builder = HttpClientBuilder.create();

但是,当我执行此请求时,我收到此异常:

java.lang.RuntimeException: org.apache.http.conn.UnsupportedSchemeException: http protocol is not supported
Caused by: org.apache.http.conn.UnsupportedSchemeException: http protocol is not supported
        at org.apache.http.impl.conn.DefaultHttpClientConnectionOperator.connect(DefaultHttpClientConnectionOperator.java:108) ~[httpclient-4.5.1.jar:4.5.1]
        at org.apache.http.impl.conn.BasicHttpClientConnectionManager.connect(BasicHttpClientConnectionManager.java:338) ~[httpclient-4.5.1.jar:4.5.1]
        at org.apache.http.impl.execchain.MainClientExec.establishRoute(MainClientExec.java:388) ~[httpclient-4.5.1.jar:4.5.1]
        at org.apache.http.impl.execchain.MainClientExec.execute(MainClientExec.java:236) ~[httpclient-4.5.1.jar:4.5.1]
        at org.apache.http.impl.execchain.ProtocolExec.execute(ProtocolExec.java:184) ~[httpclient-4.5.1.jar:4.5.1]
        at org.apache.http.impl.execchain.RetryExec.execute(RetryExec.java:88) ~[httpclient-4.5.1.jar:4.5.1]
        at org.apache.http.impl.execchain.RedirectExec.execute(RedirectExec.java:110) ~[httpclient-4.5.1.jar:4.5.1]
        at org.apache.http.impl.client.InternalHttpClient.doExecute(InternalHttpClient.java:184) ~[httpclient-4.5.1.jar:4.5.1]
        at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:82) ~[httpclient-4.5.1.jar:4.5.1]
        at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:107) ~[httpclient-4.5.1.jar:4.5.1]
        at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:55) ~[httpclient-4.5.1.jar:4.5.1]

(为简洁起见,例外缩短了)

由于这是一个HTTP代理,我不想将方案更改为HTTPS,无论如何这都不起作用。我如何让它工作?


答案 1

java.lang.RuntimeException: org.apache.http.conn.UnsupportedSchemeException: http protocol is not support

为什么会出现此问题?

答:这实际上会发生,因为.you forget to register a connection socket factory for the 'http' scheme

在使用隧道之前,必须使用普通方案来建立与代理本身的中间连接。'http''https'


出于操作目的,您可以尝试以下代码:

CloseableHttpClient client = HttpClients.custom()
           .setRoutePlanner(new
 SystemDefaultRoutePlanner(ProxySelector.getDefault()))
           .build();

我也会建议简单的代码用于您的研究。希望它能拯救你。

ClientExecuteProxy.java

package org.apache.http.examples.client;

import org.apache.http.HttpHost;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;

/**
 * How to send a request via proxy.
 *
 * @since 4.0
 */
public class ClientExecuteProxy {

    public static void main(String[] args)throws Exception {
        CloseableHttpClient httpclient = HttpClients.createDefault();
        try {
            HttpHost target = new HttpHost("httpbin.org", 443, "https");
            HttpHost proxy = new HttpHost("127.0.0.1", 8080, "http");

            RequestConfig config = RequestConfig.custom()
                    .setProxy(proxy)
                    .build();
            HttpGet request = new HttpGet("/");
            request.setConfig(config);

            System.out.println("Executing request " + request.getRequestLine() + " to " + target + " via " + proxy);

            CloseableHttpResponse response = httpclient.execute(target, request);
            try {
                System.out.println("----------------------------------------");
                System.out.println(response.getStatusLine());
                System.out.println(EntityUtils.toString(response.getEntity()));
            } finally {
                response.close();
            }
        } finally {
            httpclient.close();
        }
    }

}

您是否正在使用 CloudantClient Java API for Cloudant DB?

答:

如果是,那么事实证明,设置代理时HTTP的问题是我们的一个错误(对此感到抱歉)。我们解决了这个问题。您可以从此处下载jar文件。(摘自迈克-罗兹的回答released 1.2.1)


更新

如何在此处指定代理的凭据?

HTTP 身份验证

默认情况下,httpclient 不会抢先提供凭据 。这是设计使然,作为安全预防措施,并作为规范的一部分。但是,如果您不重试连接,或者您正在连接的任何位置都希望您在第一个连接上发送身份验证详细信息,则这会导致问题。它还会导致请求出现额外的延迟,因为您需要进行多次调用,并导致 401 出现在日志中。it will first create a HTTP request without authentication parameters

解决方法是使用身份验证缓存来假装您已经连接到服务器一次。这意味着您只能进行一次 HTTP 调用。

CloseableHttpClient httpclient = HttpClientBuilder.create().build();

HttpHost targetHost = new HttpHost("localhost", 80, "http");
CredentialsProvider credsProvider = new BasicCredentialsProvider();
credsProvider.setCredentials(
        new AuthScope(targetHost.getHostName(), targetHost.getPort()),
        new UsernamePasswordCredentials("username", "password"));

// Create AuthCache instance
AuthCache authCache = new BasicAuthCache();
// Generate BASIC scheme object and add it to the local auth cache
BasicScheme basicAuth = new BasicScheme();
authCache.put(targetHost, basicAuth);

// Add AuthCache to the execution context
HttpClientContext context = HttpClientContext.create();
context.setCredentialsProvider(credsProvider);
context.setAuthCache(authCache);

HttpGet httpget = new HttpGet("/");
for (int i = 0; i < 3; i++) {
    CloseableHttpResponse response = httpclient.execute(
            targetHost, httpget, context);
    try {
        HttpEntity entity = response.getEntity();

    } finally {
        response.close();
    }
}

注意:您需要信任要连接到的主机,如果您使用的是HTTP,则您的用户名和密码将以明文形式发送(好吧,base64,但这不算在内)。

您还应该使用更具体的Authscope,而不是依赖和喜欢您的示例。AuthScope.ANY_HOSTAuthScope.ANY_PORT

功劳归于Cetra

相关链接:

  1. HttpClientBuilder basic auth
  2. Apache HttpClient 4.1 - Proxy Authentication

答案 2

你所拥有的应该非常接近工作。我会做以下简单的更改:

builder.useSystemProperties();

删除使用系统属性的调用。它没有很好地记录,但是当您设置代理时(就像您在下一行中所做的那样),它会覆盖它,因此只需删除该行即可。

builder.setProxy(new HttpHost(proxyHost, proxyPort));

使用显式的“scheme”参数调用 HttpHost 构造函数。这是您收到错误的地方,因此请将其明确说明:

String proxyScheme = "http";
builder.setProxy(new HttpHost(proxyHost, proxyPort, proxyScheme));

注意:你没有说,但基于“BasicCredentialsProvider”的用法,这只是给你“Basic”身份验证。Basic只是编码的,并不真正安全。对于 Digest 或 NTLM 或 Kerberos,您将需要不同的代码。


推荐