HTTPClient在使用Basic Auth时发出两个请求?

时间:2022-10-03 20:29:56

I have been using HTTPClient version 4.1.2 to try to access a REST over HTTP API that requires Basic Authentication. Here is client code:

我一直在使用HTTPClient version 4.1.2尝试通过HTTP API访问需要基本身份验证的REST。这是客户端代码:

DefaultHttpClient httpClient = new DefaultHttpClient(new ThreadSafeClientConnManager());
// Enable HTTP Basic Auth
httpClient.getCredentialsProvider().setCredentials(
    new AuthScope(AuthScope.ANY_HOST, AuthScope.ANY_PORT), 
    new UsernamePasswordCredentials(this.username, this.password));

HttpHost proxy = new HttpHost(this.proxyURI.getHost(), this.proxyURI.getPort());

httpClient.getParams().setParameter(ConnRouteParams.DEFAULT_PROXY, proxy);

When I construct a POST request, like this:

当我构造一个POST请求时,比如:

HttpPost request = new HttpPost("http://my/url");
request.addHeader(new BasicHeader("Content-type", "application/atom+xml; type=entry")); // required by vendor
request.setEntity(new StringEntity("My content"));

HttpResponse response = client.execute(request);

I see in Charles Proxy that there are two requests being sent. One without the Authorization: Basic ... header and one with it. The first one fails with a 401, as you would expect, but the second goes through just fine with a 201.

我在Charles Proxy中看到有两个请求被发送。一个未经授权的:Basic…标题和一个。正如你所预期的,第一个是401退休金计划失败,第二个是201养老金计划。

Does anyone know why this happens? Thanks!

有人知道这是为什么吗?谢谢!

EDIT:

编辑:

I should make clear that I have already looked at this question, but as you can see I set the AuthScope the same way and it didn't solve my problem. Also, I am creating a new HttpClient every time I made a request (though I use the same ConnectionManager), but even if I use the same HttpClient for multiple requests, the problem still persists.

我应该澄清一下,我已经看了这个问题,但是你可以看到我用同样的方法设置了AuthScope,它并没有解决我的问题。此外,每当我提出请求时,我都会创建一个新的HttpClient(尽管我使用的是同一个ConnectionManager),但即使我对多个请求使用相同的HttpClient,这个问题仍然存在。

EDIT 2:

编辑2:

So it looks like what @LastCoder was suggesting is the way to do. See this answer to another question. The problem stems from my lack of knowledge around the HTTP spec. What I'm looking to do is called "preemptive authentication" and the HttpClient docs mention it here. Thankfully, the answer linked to above is a much shorter and cleaner way to do it.

看起来@LastCoder的建议是这样的。请看另一个问题的答案。这个问题源于我对HTTP规范缺乏了解,我希望做的是“抢占式认证”,HttpClient docs在这里提到了它。值得庆幸的是,与上面相关的答案是一种更短、更干净的方法。

2 个解决方案

#1


10  

Rather than using .setCredentials() why don't you just encode USERNAME:PASSWORD and add the authentication header with .addHeader()

与其使用.setCredentials(),不如直接编码用户名:密码,然后用.addHeader()添加验证头

#2


2  

This means that your server/target endpoint is creating a new session for every client request. This forces every request of yours to go through a hand-shake, which means the clients first makes the call and realizes that it needs authorization, then it follows with the authorization. What you need to do is send the authorization preemptively as follows:

这意味着您的服务器/目标端点正在为每个客户端请求创建一个新的会话。这将迫使您的每个请求都进行握手,这意味着客户端首先进行调用并意识到它需要授权,然后再进行授权。您需要做的是先发送授权如下:

httpClient.getParams().setAuthenticationPreemptive(true);

httpClient.getParams().setAuthenticationPreemptive(真正的);

Just to understand the process you may log your client request headers, to give you an idea of what your client is sending and receiving: See if this works.

为了理解这个过程,您可以记录您的客户端请求头,以了解您的客户端正在发送和接收什么:看看这是否有效。

#1


10  

Rather than using .setCredentials() why don't you just encode USERNAME:PASSWORD and add the authentication header with .addHeader()

与其使用.setCredentials(),不如直接编码用户名:密码,然后用.addHeader()添加验证头

#2


2  

This means that your server/target endpoint is creating a new session for every client request. This forces every request of yours to go through a hand-shake, which means the clients first makes the call and realizes that it needs authorization, then it follows with the authorization. What you need to do is send the authorization preemptively as follows:

这意味着您的服务器/目标端点正在为每个客户端请求创建一个新的会话。这将迫使您的每个请求都进行握手,这意味着客户端首先进行调用并意识到它需要授权,然后再进行授权。您需要做的是先发送授权如下:

httpClient.getParams().setAuthenticationPreemptive(true);

httpClient.getParams().setAuthenticationPreemptive(真正的);

Just to understand the process you may log your client request headers, to give you an idea of what your client is sending and receiving: See if this works.

为了理解这个过程,您可以记录您的客户端请求头,以了解您的客户端正在发送和接收什么:看看这是否有效。