HttpURLConnection.getResponseCode()奇怪的行为

时间:2017-11-10 07:53:56

标签: java sockets httpurlconnection urlconnection

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中所述的单个请求。我用BurpSuite链接了JVM,这是一个非常好的代理,所以我很确定它不是代理问题或者类似的东西。

如果有人能帮助我并解释我为什么会发生,我真的很感激。

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

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

[编辑]

我发布了通讯的标题:

不使用cookies:

Request1:

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

Response1:

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;

Request2:

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会发生这种情况:

Request1 with cookies:

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

带有cookies的Response1:

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;

Request2 with cookies:

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

带有cookies的Response2:

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

2 个答案:

答案 0 :(得分:1)

您所描述的是具有身份验证的HTTP如何工作。第一个请求发生时没有凭据。具有状态代码401的服务器的响应告诉客户端需要认证,并且还包含支持/接受认证机制的信息。客户端使用此信息创建后续请求,包括身份验证。

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

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

要了解发生了什么,您可以启动一个像Wireshark这样的网络分析器,您可以在其中查看每个erquest /响应周期的请求和响应。

使用您提供的跟踪,似乎服务器需要您的cookie值来在身份验证后跟踪您的会话。这就是为什么你得到“401 Unauthorized”作为回应。

答案 1 :(得分:-1)

我刚刚发现我的JVM使用的是sun.net.www.protocol.http.HttpURLConnection,作为java.net.HttpURLConnection的一个实现,这是一个充满bug的类。您可能想看一下我发现有帮助的post

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

完成

在我的情况下,我无法找到解决我的问题的任何方法,但无论如何它只是一些额外的GET请求,jsut会增加你的流量一点点,并不像一些POST那样灾难性的要求重复。

PS:如果有人有一些建议/解决方案,我会很高兴听到它们。