我有以下代码:

        HttpURLConnection conn = null;
        BufferedReader in = null;
        StringBuilder sb = null;
        InputStream is = null;
        conn = (HttpURLConnection) url.openConnection();
        // Break-point A
        conn.setDoInput(true);
        conn.setDoOutput(true);
        conn.setRequestMethod("POST");
        // Break-point B
        conn.setRequestProperty("X-TP-APP", Constants.X_TP_APP);
        conn.setRequestProperty("X-TP-DEVICE", Constants.X_TP_DEVICE);
        conn.setRequestProperty("X-TP-LOCALE", Constants.X_TP_LOCALE);
        conn.setRequestProperty("Content-Type", contentType);
        conn.setRequestProperty("Accept", accept);
        conn.setRequestProperty("Authorization", SystemApi.TOKEN_STR);
        conn.setUseCaches(false);
        conn.setConnectTimeout(30000);
        conn.getOutputStream().write(req.getBytes("UTF-8"));
        conn.getOutputStream().flush();
        conn.getOutputStream().close();
        is = conn.getInputStream();
        in = new BufferedReader(new InputStreamReader(is));
        int statusCode = conn.getResponseCode();
        // Break-point C


代码运行正常,没有问题(禁用断点(A,B)时)

我试图找出HttpURLConnection何时真正调用请求并将断点(A)放在conn = getConnection(strURL);之后
并继续执行代码,但是最后,在断点(C),服务器将返回401-未经授权,这意味着我的Authorization标头不在请求中。

似乎我们正在尝试先打开一个连接,然后尽可能快地设置标题。如果我们不够快,那么无论如何都会调用该请求,这似乎不正确。

我的问题和关注:


HttpURLConnection何时真正调用请求?
这到底是怎么回事?这是正确的方法吗?
有没有更好的方法来确保在调用请求之前已设置标头?

最佳答案

根据文档,实际连接是在[connect()] Http上调用UrlConnection方法时建立的。这可以手动完成,也可以通过某些其他方法隐式完成。 UrlConnection.connect()的Javadocs部分说:


  URLConnection对象经历两个阶段:首先创建它们,然后将它们连接。在创建之后和连接之前,可以指定各种选项(例如doInput和UseCaches)。连接后,尝试设置它们是错误的。如果需要,依赖于连接的操作(如getContentLength)将隐式执行连接。


特别要注意最后一句话。我在您的代码中看不到任何需要在第一个conn.getOutputStream()之前建立连接的内容,并且我读文档时说,连接对象只有在对其调用某种方法之后才会进入“已连接”状态这需要。在此之前,可以设置连接属性。

而且,文档明确指出,在连接对象已经连接时调用设置连接属性(尤其是setRequestProperty())的属性的方法将抛出IllegalStateException

您的Java库很可能以您描述的方式出现故障,但这肯定与API规范冲突。我认为您所观察到的行为的解释很有可能是不同的,我建议您捕获并分析实际的HTTP流量以确定实际发生的情况。

09-10 08:59
查看更多