Java 如何将 HttpClientBuilder 与 Http 代理一起使用?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/36268092/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to use HttpClientBuilder with Http proxy?
提问by jobin
I am trying to set proxy for a request I am making using HttpClientBuilder
as follows:
我正在尝试为我正在使用的请求设置代理,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());
where builder is:
建造者在哪里:
HttpClientBuilder builder = HttpClientBuilder.create();
However, I get this exception when I execute this request:
但是,当我执行此请求时出现此异常:
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 shortened for brevity)
(为简洁起见缩短了例外)
Since this is an HTTP proxy, I don't want to change the scheme to HTTPS, which anyways won't work. How do I get this working?
由于这是一个 HTTP 代理,我不想将方案更改为 HTTPS,这无论如何都行不通。我如何让这个工作?
回答by An Do
I think the problem is with your HttpClient, not the proxy. Did you try to create your HttpClient by using HttpClientBuilder.build()
我认为问题在于您的 HttpClient,而不是代理。您是否尝试使用 HttpClientBuilder.build() 创建您的 HttpClient
HttpClient client = builder.build();
回答by SkyWalker
java.lang.RuntimeException: org.apache.http.conn.UnsupportedSchemeException: http protocol is not supported
java.lang.RuntimeException: org.apache.http.conn.UnsupportedSchemeException: 不支持 http 协议
Why this problem occurs?
为什么会出现这个问题?
Ans:This actually happens because you forget to register a connection socket factory for the 'http' scheme
.
Ans:这实际上是因为you forget to register a connection socket factory for the 'http' scheme
.
Plain 'http'
scheme must be used to establish an intermediate connection
to the proxy itself before 'https'
tunneling could be employed.
'http'
在使用'https'
隧道之前,必须使用普通方案来建立与代理本身的中间连接。
For operational purpose, you can try this code:
出于操作目的,您可以尝试以下代码:
CloseableHttpClient client = HttpClients.custom()
.setRoutePlanner(new
SystemDefaultRoutePlanner(ProxySelector.getDefault()))
.build();
I would also suggest simple code for your research. Hope it can save you.
我还会为您的研究建议简单的代码。希望它能救你。
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?
您是否将 CloudantClient java API 用于 Cloudant DB?
Ans:
答:
If YES, then It turned out the issue with HTTP when setting a proxy was a bug at our end (sorry about that). We released 1.2.1
with the fix for this problem. You can download jar file from here. (Collected from mike-rhodes's answer)
如果是,那么事实证明,设置代理时 HTTP 的问题是我们最终的错误(对此很抱歉)。我们released 1.2.1
解决了这个问题。你可以从这里下载 jar 文件。(从迈克罗兹的回答中收集)
UPDATE
更新
How do I specify the credentials for the proxy here?
如何在此处指定代理的凭据?
From HTTP authentication,
By default, httpclient will not provide credentials preemptively, it will first create a HTTP request without authentication parameters
. This is by design, as a security precaution, and as part of the spec. But, this causes issues if you don't retry the connection, or wherever you're connecting to expects you to send authentication details on the first connection. It also causes extra latency to a request, as you need to make multiple calls, and causes 401s to appear in the logs.
默认情况下,httpclient 不会抢先提供凭据,it will first create a HTTP request without authentication parameters
. 这是设计使然,作为安全预防措施,并且作为规范的一部分。但是,如果您不重试连接,或者您连接到的任何地方都希望您在第一次连接时发送身份验证详细信息,则会导致问题。它还会给请求造成额外的延迟,因为您需要进行多次调用,并导致 401 出现在日志中。
The workaround is to use an authentication cache to pretend that you've already connected to the server once. This means you'll only make one HTTP call.
解决方法是使用身份验证缓存来假装您已经连接到服务器一次。这意味着您将只进行一次 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
andAuthScope.ANY_PORT
like in your example.
注意:您需要信任您正在连接的主机,如果您使用 HTTP,您的用户名和密码将以明文形式发送(好吧,base64,但这不算数)。
您还应该使用更具体的 Authscope,而不是依赖
AuthScope.ANY_HOST
和AuthScope.ANY_PORT
喜欢您的示例。
Credit goes to Cetra
幸得外贸协会
Related Links:
相关链接:
回答by JoeG
What you have should be very close to working. I would make the following simple changes:
你所拥有的应该非常接近工作。我会做以下简单的改变:
builder.useSystemProperties();
Delete the call to useSystemProperties. It isn't documented well, but when you set the Proxy (as you do in the next line), it overrides this, so just remove that line.
删除对 useSystemProperties 的调用。它没有很好地记录,但是当您设置代理时(就像您在下一行中所做的那样),它会覆盖它,因此只需删除该行。
builder.setProxy(new HttpHost(proxyHost, proxyPort));
Call the HttpHost constructor with the explicit 'scheme' parameter. This is where you are getting the error, so make it explicit:
使用显式“方案”参数调用 HttpHost 构造函数。这是您收到错误的地方,因此请明确说明:
String proxyScheme = "http";
builder.setProxy(new HttpHost(proxyHost, proxyPort, proxyScheme));
Note: you did not say, but based on the usage of "BasicCredentialsProvider", this is only giving you "Basic" authentication. Basic is only encoded and is not really secure. For Digest or NTLM or Kerberos you will need different code.
注意:你没有说,但根据“BasicCredentialsProvider”的用法,这只是给你“基本”身份验证。Basic 仅经过编码,并不真正安全。对于 Digest 或 NTLM 或 Kerberos,您将需要不同的代码。