Как использовать HttpClientBuilder с Http-прокси?
Я пытаюсь установить прокси для запроса, который я делаю с помощью 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, которая в любом случае не будет работать. Как мне заставить это работать?
4 ответа
java.lang.RuntimeException: org.apache.http.conn.UnsupportedSchemeException: протокол http не поддерживается
Почему эта проблема возникает?
Ответ: это на самом деле происходит потому, что you forget to register a connection socket factory for the 'http' scheme
,
гладкий 'http'
Схема должна использоваться для установления промежуточного соединения с самим прокси до того, как 'https'
туннелирование может быть использовано.
Для оперативного использования вы можете попробовать этот код:
CloseableHttpClient client = HttpClients.custom()
.setRoutePlanner(new
SystemDefaultRoutePlanner(ProxySelector.getDefault()))
.build();
Я бы также предложил простой код для вашего исследования. Надеюсь, это может спасти вас.
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 для Cloudant DB?
Ans:
Если ДА, то оказалось, что проблема с HTTP при настройке прокси была ошибкой с нашей стороны (извините за это). Мы released 1.2.1
с исправлением этой проблемы. Вы можете скачать файл JAR здесь. ( Mike Rhodes)
ОБНОВИТЬ
Как мне указать учетные данные для прокси здесь?
По умолчанию httpclient не будет предоставлять учетные данные в приоритетном порядке, it will first create a HTTP request without authentication parameters
, Это сделано специально, в качестве меры безопасности и как часть спецификации. Но это вызывает проблемы, если вы не повторяете соединение или куда бы вы ни подключались, вы ожидаете, что вы отправите данные аутентификации при первом соединении. Это также приводит к дополнительной задержке запроса, так как вам нужно сделать несколько звонков, и заставляет 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();
}
}
NB. Вам нужно доверять хосту, к которому вы подключаетесь, и если вы используете HTTP, ваши имя пользователя и пароль будут отправлены в виде открытого текста (ну, base64, но это не считается).
Вы также должны использовать гораздо более конкретный Authscope, а не полагаться на
AuthScope.ANY_HOST
а такжеAuthScope.ANY_PORT
как в вашем примере.
Кредит идет в Cetra
Ссылки по теме:
То, что у вас есть, должно быть очень близко к работе. Я бы сделал следующие простые изменения:
builder.useSystemProperties();
Удалите вызов для использования SystemProperties. Это плохо документировано, но когда вы устанавливаете Proxy (как вы делаете в следующей строке), он переопределяет это, поэтому просто удалите эту строку.
builder.setProxy(new HttpHost(proxyHost, proxyPort));
Вызовите конструктор HttpHost с явным параметром "схема". Вот где вы получаете ошибку, поэтому сделайте ее явной:
String proxyScheme = "http";
builder.setProxy(new HttpHost(proxyHost, proxyPort, proxyScheme));
Примечание: вы не сказали, но, основываясь на использовании "BasicCredentialsProvider", это дает вам только "базовую" аутентификацию. Basic только закодирован и не очень безопасен. Для дайджеста, NTLM или Kerberos вам понадобится другой код.
Я думаю, что проблема с вашим HttpClient, а не прокси. Вы пытались создать свой HttpClient с помощью HttpClientBuilder.build()
HttpClient client = builder.build();
ChallengeState.PROXY предоставит заголовок авторизации прокси. Однако начиная с версии 4.3 этот код устарел. Он все еще работает в версии 4.5.
HttpHost proxyHost = this.getProxyHttpHost(config);
authCache.put(proxyHost, new BasicScheme(ChallengeState.PROXY));
Другой способ иметь заголовок прокси-авторизации
credsProvider.setCredentials(new AuthScope("127.0.0.1","8080"),
new UsernamePasswordCredentials("username", "password"));
builder.setProxyAuthenticationStrategy(new ProxyAuthenticationStrategy());
builder.setDefaultCredentialsProvider(credsProvider);