【发布时间】:2016-01-04 15:33:44
【问题描述】:
我正在尝试通过具有基本身份验证的代理使用 HTTP 客户端 4.4 发送请求。 如果我输入正确的凭据,则连接成功。
但如果我输入了错误的凭据,即使使用正确的凭据,以下所有其他连接尝试都会失败。
似乎一旦我们第一次提供了(错误的)凭据,就永远不会发送新的(正确或错误的)凭据。
你会看到有两个调用:
- 第一次调用,错误的代理凭据
- 第二次调用,正确的代理凭据
代码:
package test;
import org.apache.commons.codec.binary.Base64;
import org.apache.http.HttpHost;
import org.apache.http.HttpResponse;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.client.HttpClients;
public class Main {
private HttpClient client;
private HttpClientContext context = HttpClientContext.create();
public static void main(String[] args) throws Exception {
System.setProperty("org.apache.commons.logging.Log", "org.apache.commons.logging.impl.SimpleLog");
System.setProperty("org.apache.commons.logging.simplelog.showdatetime", "true");
System.setProperty("org.apache.commons.logging.simplelog.log.org.apache.http", "DEBUG");
System.setProperty("org.apache.commons.logging.simplelog.log.org.apache.http.wire", "ERROR");
Main main = new Main();
main.createHttpClient();
main.send(true, "test", "wrong"); // 1st call, wrong credentials, if this call is removed, it works !
main.send(true, "test", "correct"); // 2nd call, correct credentials
}
public void send(String username, String password) throws Exception {
proxyAuthenticate(username, password);
HttpUriRequest request = new HttpGet("https://the-backend.xyz");
HttpResponse httpResponse = client.execute(request, context);
int statusCode = httpResponse.getStatusLine().getStatusCode();
System.out.println("######################### " + statusCode);
}
public void createHttpClient() throws Exception {
HttpClientBuilder httpClientBuilder = HttpClients.custom();
httpClientBuilder.setProxy(new HttpHost("proxy.the-proxy.xyz", 1234));
client = httpClientBuilder.build();
}
private void proxyAuthenticate(String username, String password) {
UsernamePasswordCredentials credentials = new UsernamePasswordCredentials(username, password);
AuthScope scope = new AuthScope("proxy.the-proxy.xyz", 1234);
CredentialsProvider provider = new BasicCredentialsProvider();
provider.setCredentials(scope, credentials);
context.setCredentialsProvider(provider);
}
}
第一次尝试的日志(使用错误的代理凭据连接:两个 http 请求一个没有凭据,一个有凭据,都返回 407,看起来合乎逻辑):
2015/10/07 13:39:02:502 CEST [警告] BasicAuthCache - 意外的 I/O 序列化身份验证方案 java.io.NotSerializableException 时出错:test.Main at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1183) 在 java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1547) 在 java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1508) 在 java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1431) 在 java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1177) 在 java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:347) 在 org.apache.http.impl.client.BasicAuthCache.put(BasicAuthCache.java:107) 在 test.Main.proxyAuthenticate(Main.java:109) 在 test.Main.send(Main.java:56) 在 test.Main2.main(Main2.java:30)
2015/10/07 13:39:02:502 CEST [调试] RequestAddCookies - CookieSpec 已选择:默认 2015/10/07 13:39:02:502 CEST [DEBUG] PoolingHttpClientConnectionManager - 连接请求:[路由: {tls}->http://proxy.the-proxy.xyz:1234->https://the-backend.xyz:443][total 保持活力:0;分配的路线:3 条中的 0 条;总分配:3 个中的 0 个] 2015/10/07 13:39:02:502 CEST [调试] PoolingHttpClientConnectionManager - 连接租用:[id:1][路由: {tls}->http://proxy.the-proxy.xyz:1234->https://the-backend.xyz:443][total 保持活力:0;分配的路线:3 条中的 1 条;总分配:1 of 3] 2015/10/07 13:39:02:502 CEST [调试] MainClientExec - 开放 联系 {tls}->http://proxy.the-proxy.xyz:1234->https://the-backend.xyz:443 2015/10/07 13:39:02:502 CEST [调试] DefaultHttpClientConnectionOperator - 连接到 proxy.the-proxy.xyz/123.45.67.890:1234 2015/10/07 13:39:07:530 CEST [DEBUG] DefaultHttpClientConnectionOperator - 已建立连接 321.54.76.098:58216123.45.67.890:1234 2015/10/07 13:39:07:530 CEST [DEBUG] 标头 - http-outgoing-1 >> CONNECT the-backend.xyz:443 HTTP/1.1 2015/10/07 13:39:07:530 CEST [DEBUG] 标头 - http-outgoing-1 >> 主机: the-backend.xyz 2015/10/07 13:39:07:530 CEST [调试] 标头 - http-outgoing-1 >> 用户代理:Apache-HttpClient/4.4.1 (Java/1.7.0_51) 2015/10/07 13:39:07:530 CEST [DEBUG] 标头- http-outgoing-1 123.45.67.890:1234 2015/10/07 13:39:12:560 CEST [DEBUG] HttpAuthenticator - 生成对身份验证的响应 使用基本方案的挑战 2015/10/07 13:39:12:560 CEST [DEBUG] 标头 - http-outgoing-1 >> CONNECT the-backend.xyz:443 HTTP/1.1 2015/10/07 13:39:12:560 CEST [DEBUG] 标头 - http-outgoing-1 >> 主机: the-backend.xyz 2015/10/07 13:39:12:560 CEST [调试] 标头 - http-outgoing-1 >> 用户代理:Apache-HttpClient/4.4.1 (Java/1.7.0_51) 2015/10/07 13:39:12:560 CEST [DEBUG] 标头- http-outgoing-1 >> 代理授权:基本 xXXXxxXxXXXXXX 2015/10/07 13:39:12:561 CEST [DEBUG] 标头 - http-outgoing-1 http://proxy.the-proxy.xyz:1234 2015/10/07 13:39:12:561 CEST [调试] DefaultManagedHttpClientConnection - http-outgoing-1:关闭连接 2015/10/07 13:39:12:561 CEST [调试] MainClientExec - CONNECT 被拒绝 通过代理:HTTP/1.1 407 需要代理身份验证 2015/10/07 13:39:12:561 CEST [调试] DefaultManagedHttpClientConnection - http-outgoing-1:关闭连接 2015/10/07 13:39:12:561 CEST [调试] MainClientExec - 连接被丢弃 2015/10/07 13:39:12:561 CEST [调试] DefaultManagedHttpClientConnection - http-outgoing-1:关闭 连接 2015/10/07 13:39:12:561 CEST [调试] PoolingHttpClientConnectionManager - 连接已释放:[id: 1][路线: {tls}->http://proxy.the-proxy.xyz:1234->https://the-backend.xyz:443][total 保持活力:0;分配的路线:3 条中的 0 条;总分配:3 个中的 0 个]
################### 407
第二次尝试的日志(使用正确的代理凭据连接:只有一个 http 请求,为什么没有第二次使用正确凭据的请求???):
2015/10/07 13:39:17:585 CEST [警告] BasicAuthCache - 意外的 I/O 序列化身份验证方案 java.io.NotSerializableException 时出错:test.Main at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1183) 在 java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1547) 在 java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1508) 在 java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1431) 在 java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1177) 在 java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:347) 在 org.apache.http.impl.client.BasicAuthCache.put(BasicAuthCache.java:107) 在 test.Main.proxyAuthenticate(Main.java:109) 在 test.Main.send(Main.java:56) 在 test.Main2.main(Main2.java:32)
2015/10/07 13:39:17:585 CEST [调试] RequestAddCookies - CookieSpec 已选择:默认 2015/10/07 13:39:17:585 CEST [DEBUG] PoolingHttpClientConnectionManager - 连接请求:[路由: {tls}->http://proxy.the-proxy.xyz:1234->https://the-backend.xyz:443][total 保持活力:0;分配的路线:3 条中的 0 条;总分配:3 个中的 0 个] 2015/10/07 13:39:17:585 CEST [调试] PoolingHttpClientConnectionManager - 连接租用:[id: 2][route: {tls}->http://proxy.the-proxy.xyz:1234->https://the-backend.xyz:443][total 保持活力:0;分配的路线:3 条中的 1 条;总分配:1 of 3] 2015/10/07 13:39:17:585 CEST [调试] MainClientExec - 开放 联系 {tls}->http://proxy.the-proxy.xyz:1234->https://the-backend.xyz:443 2015/10/07 13:39:17:585 CEST [调试] DefaultHttpClientConnectionOperator - 连接到 proxy.the-proxy.xyz/123.45.67.890:1234 2015/10/07 13:39:17:585 CEST [调试] DefaultHttpClientConnectionOperator - 已建立连接 321.54.76.098:58218123.45.67.890:1234 2015/10/07 13:39:17:586 CEST [DEBUG] 标头 - http-outgoing-2 >> CONNECT the-backend.xyz:443 HTTP/1.1 2015/10/07 13:39:17:586 CEST [DEBUG] 标头 - http-outgoing-2 >> 主机: the-backend.xyz 2015/10/07 13:39:17:586 CEST [调试] 标头 - http-outgoing-2 >> 用户代理:Apache-HttpClient/4.4.1 (Java/1.7.0_51) 2015/10/07 13:39:17:586 CEST [DEBUG] 标头- http-outgoing-2 http://proxy.the-proxy.xyz:1234->https://the-backend.xyz:443][total 保持活力:0;分配的路线:3 条中的 0 条;总分配:3 个中的 0 个]
################### 407
知道为什么在第二次尝试时,它在没有身份验证(正常)的情况下尝试,服务器回复说需要基本身份验证,然后它没有尝试使用正确的凭据,而是关闭了连接。
谢谢!
更新:
如果我将 HttpClient(从 4.4)更改为 DefaultHttpClient(从 4.3)并调整这两种方法,它就可以工作。 请注意,在 4.3 中从客户端调用 getCredentialsProvider,在 4.4 中从上下文调用!!!
我第一次收到 407 状态代码,但第二次收到 200,这是我所期望的。
public void createHttpClient() throws Exception {
client = new DefaultHttpClient();
HttpHost proxy = new HttpHost("proxy.eurocontrol.be", 9513);
ConnRouteParams.setDefaultProxy(client.getParams(), proxy);
}
private void proxyAuthenticate(String username, String password) {
UsernamePasswordCredentials credentials = new UsernamePasswordCredentials(username, password);
AuthScope scope = new AuthScope("proxy.eurocontrol.be", 9513);
client.getCredentialsProvider().setCredentials(scope, credentials);
// Called from client !!!!!!!!!!!!!!!!!
}
【问题讨论】:
标签: java apache-httpclient-4.x