HttpURLConnection.getResponseCode() 奇怪的行为

HttpURLConnection.getResponseCode() weird behaviour

import java.io.IOException;
import java.net.Authenticator;
import java.net.CookieHandler;
import java.net.CookieManager;
import java.net.CookiePolicy;
import java.net.HttpURLConnection;
import java.net.PasswordAuthentication;
import java.net.URL;

public class Test {

    private static class UserAuthenticator extends Authenticator {
        @Override
        protected PasswordAuthentication getPasswordAuthentication() {
            return new PasswordAuthentication("username", "password".toCharArray());
        }
    }

    public static void main(String[] args) {
        System.setProperty("http.proxyHost", "127.0.0.1");
        System.setProperty("http.proxyPort", "8080");

        Authenticator.setDefault(new UserAuthenticator());
        //CookieManager cookieManager = new CookieManager(null, CookiePolicy.ACCEPT_ORIGINAL_SERVER);
        //CookieHandler.setDefault(cookieManager);

        try {
            URL url = new URL("http://123.123.123.123");
            HttpURLConnection httpCon = (HttpURLConnection) url.openConnection(); //Connection is still close

            int code = httpCon.getResponseCode(); //Instead of generating a single request, this generates a bunch of them 
        } catch (IOException e) {}
    }
}

getResponceCode() 方法生成对服务器的多个请求,而不是 JavaDocs 中所述的单个请求。我将 JVM 与 BurpSuite 链接在一起,这是一个非常好的代理,所以我很确定这不是代理问题或类似问题。

如果有人能帮助我并向我解释 为什么会这样,我将不胜感激

我还想提一下,如果启用 cookies 管理器,它只会生成两个请求。第一个获得 401 响应代码,第二个获得 299 响应代码(这意味着第二个请求成功),然后停止。 为什么会这样?

此外,在第一次请求时不发送身份验证凭据,但在第二次之后的每个请求中都会发送身份验证凭据。 为什么会这样?

[编辑]

我正在发布通讯的headers:

不使用 cookie:

请求 1 :

GET / HTTP/1.1
User-Agent: Java/1.8.0_144
Host: 192.168.1.1
Accept: text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2
Connection: close

响应 1:

HTTP/1.0 401 Unauthorized
Date: Fri, 10 Nov 2017 11:56:36 GMT
Server: Boa/0.94.13
Connection: close
WWW-Authenticate: Basic realm="H108NS"
Content-Type: text/html; charset=ISO-8859-1
Set-Cookie: SESSIONID=4ee8135d;

请求 2 :

GET / HTTP/1.1
User-Agent: Java/1.8.0_144
Host: 192.168.1.1
Accept: text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2
Authorization: Basic YWRtaW46cGFzc3dvcmQ=
Connection: close

响应2:

HTTP/1.0 401 Unauthorized
Date: Fri, 10 Nov 2017 11:56:38 GMT
Server: Boa/0.94.13
Connection: close
WWW-Authenticate: Basic realm="H108NS"
Content-Type: text/html; charset=ISO-8859-1
Set-Cookie: SESSIONID=2ac98489;

Request2和Response2重复了大约10-20次。 这是没有饼干。尝试使用 cookie 会发生这种情况:

带有 cookie 的请求 1:

GET / HTTP/1.1
User-Agent: Java/1.8.0_144
Host: 192.168.1.1
Accept: text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2
Connection: close

使用 cookie 的响应 1:

HTTP/1.0 401 Unauthorized
Date: Fri, 10 Nov 2017 12:02:01 GMT
Server: Boa/0.94.13
Connection: close
WWW-Authenticate: Basic realm="H108NS"
Content-Type: text/html; charset=ISO-8859-1
Set-Cookie: SESSIONID=4b33e52e;

带有 cookie 的请求 2:

GET / HTTP/1.1
User-Agent: Java/1.8.0_144
Host: 192.168.1.1
Accept: text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2
Authorization: Basic YWRtaW46cGFzc3dvcmQ=
Cookie: SESSIONID=4b33e52e
Connection: close

使用 cookie 的响应 2:

HTTP/1.0 200 OK
Content-type: text/html;charset=ISO-8859-1

您所描述的是带有身份验证的 HTTP 是如何工作的。第一个请求是在没有凭据的情况下发生的。状态代码为 401 的服务器响应告诉客户端需要身份验证,还包含身份验证机制的信息 supported/accepted。客户端使用此信息创建包含身份验证的后续请求。

根据身份验证机制,您可能会看到两个以上的请求,例如NTLM 会导致几个请求-响应周期。在您的情况下,我假设 BASIC 或 DIGEST 身份验证确实发生了。

由于 HTTP 是无状态的,所有请求都需要身份验证信息,这就是为什么所有后续请求也包含凭据。这是依赖于机制的,所以例如再次使用 NTLM,请求中的详细信息看起来有所不同。

要查看发生了什么,您可能只需启动 Wireshark 等网络分析器,您可以在其中查看每个 erquest/response-cycle.

的请求和响应

根据您提供的跟踪,服务器似乎需要您的 cookie 值来在身份验证后跟踪您的会话。这就是为什么您会收到“401 Unauthorized”作为响应的原因。

我刚刚发现我的 JVM 正在使用 sun.net.www.protocol.http.HttpURLConnection 作为 java.net.HttpURLConnection 的实现,这是一个充满错误的 class。您可能想看看这个 post,我发现它很有帮助。

实际上有一种方法可以绕过这个问题,但仅限于发送 POST 请求的情况。这是通过将 JVM 属性 sun.net.http.retryPost 设置为 false。这可以通过 System.setProperty("sun.net.http.retryPost", "false")

来完成

在我的例子中,我无法设法解决我的问题,但无论如何,这只是一些额外的 GET 请求,这只会增加你的流量一点点,而且它不会像使用一些 POST 请求重复。

PS : 如果有人有一些 suggests/solutions 我会很高兴听到他们。