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

标签 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());

builder 在哪里:

    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]

(为简洁起见缩短的异常(exception))

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

最佳答案

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

Why this problem occurs?

回答:这实际上是因为您忘记为“http”方案注册一个连接套接字工厂

Plain '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 的问题是我们这边的一个错误(对此感到抱歉)。我们发布了 1.2.1 并修复了这个问题。您可以从here 下载jar 文件。 . (收集自mike-rhodes's answer)


更新

How do I specify the credentials for the proxy here?

来自 HTTP authentication ,

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

解决方法是使用身份验证缓存假装您已经连接到服务器一次。这意味着您只会进行一次 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: You need to trust the host you're connecting to, and if you're using HTTP, your username and password will be sent in cleartext (well, base64, but that doesn't count).

You should also be using a much more specific Authscope rather than relying on AuthScope.ANY_HOST and AuthScope.ANY_PORT like in your example.

归功于 Cetra

相关链接:

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

关于java - 如何将 HttpClientBuilder 与 Http 代理一起使用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36268092/

相关文章:

java - Spring-boot应用测试-内存问题

javascript - 浏览器的 Websocket 库?

python - 使用代理扭曲 getpage

java - Proxy 背后的 SpringBoot 适用于 Undertow 但不适用于 Tomcat

python - 请求 : [Errno 8] _ssl. c:504 的 HTTPS 代理:EOF 发生在违反协议(protocol)的情况下

authentication - pip 安装失败,需要 407 代理身份验证

java - 一种方法中的双重递归

java - 如何将 ISO 8601 日期(字符串)转换为日期?

java - 尝试在类之间写入对象时 ObjectOutputStream.writeObject() 卡住

json - REST 授权 : Username/Password in Authorization Header vs JSON body