如何在Http代理中使用HttpClientBuilder?

时间:2016-03-28 18:03:06

标签: java http proxy squid

我正在尝试使用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,无论如何都无法工作。我如何使这个工作?

3 个答案:

答案 0 :(得分:16)

  

了java.lang.RuntimeException:   org.apache.http.conn.UnsupportedSchemeException:http协议不是   支持的

Why this problem occurs?

Ans:这实际上是因为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();
        }
    }

}

Are you using using CloudantClient java API for Cloudant DB?

答案

如果是,那么在设置代理时,我发现HTTP的问题是我们最终的错误(对不起)。我们released 1.2.1解决了这个问题。您可以从here下载jar文件。 (收集自mike-rhodes's answer

更新

  

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

来自HTTP authentication

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

解决方法是使用身份验证缓存假装您已连接到服务器一次。这意味着您只能进行一次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();
    }
}
  

N.B:你需要信任你所连接的主持人,如果你是   使用HTTP,您的用户名和密码将以明文形式发送   (好吧,base64,但这不算数)。

     

您还应该使用更具体的Authscope而不是   依赖于你的AuthScope.ANY_HOSTAuthScope.ANY_PORT   示例

信用转到Cetra

相关链接:

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

答案 1 :(得分:4)

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

builder.useSystemProperties();

删除对useSystemProperties的调用。它没有被很好地记录,但是当您设置代理时(就像在下一行中那样),它会覆盖它,所以只需删除该行。

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

使用明确的&#39;方案调用HttpHost构造函数&#39;参数。这是您收到错误的地方,因此请明确说明:

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

注意:您没有说,但根据&#34; BasicCredentialsProvider&#34;的用法,这只是给你&#34; Basic&#34;认证。 Basic只是编码而且不是很安全。对于摘要或NTLM或Kerberos,您将需要不同的代码。

答案 2 :(得分:2)

我认为问题在于您的HttpClient,而不是代理。您是否尝试使用HttpClientBuilder.build()

创建HttpClient
HttpClient client = builder.build();