Android上的HttpURLConnection何时真正调用该请求

问题描述 投票:0回答:3

我有以下代码:

        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标头不在请求中。

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

我的问题和关注:

  1. HttpURLConnection何时真正调用该请求?

  2. 这是实际发生的事情吗?这是正确的方法吗?

  3. 是否有更好的方法来确保在调用请求之前已设置标题?

java android request httpurlconnection
3个回答
2
投票

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

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

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

此外,文档明确指出,如果在连接对象已经连接时调用设置连接属性(特别是setRequestProperty())的方法,则将抛出IllegalStateException

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


0
投票

实际上实际上发生的是,在调试模式下,我在表达式中使用了conn.getResponseCode(),这迫使conn.getResponseCode()运行。

尚未连接时,getResponseCode()将在准备请求之前调用connect()

因此它将返回我401。


0
投票

由于Android使用相同的HttpURLConnection,所以我做了一些捕获数据包交换的操作,以了解幕后情况。

我在这篇文章Can you explain the HttpURLConnection connection process?中详细介绍了我的实验>

概述程序的网络活动。

在断点A

没有与远程服务器建立物理连接。您将获得本地连接对象的逻辑句柄。

在断点B

您只需配置本地连接对象,仅此而已。

conn.getOutputStream()

网络连接从此处开始,但是没有有效负载传输到服务器。

conn.getInputStream()

有效负载(http标头,内容)被发送到服务器,您将获得响应(缓冲到输入流中,以及响应代码等)]

回答您的问题

HttpURLConnection何时真正调用该请求?

getInputStream()触发网络层发送应用程序有效负载并获得响应。

这是实际发生的事情吗?这是正确的方法吗?

没有openConnection()不启动网络活动。您将获得本地句柄以用于将来的连接,而不是活动的连接。

是否有更好的方法来确保在调用请求之前已设置标题?

您无需确保已设置标题。在您请求响应(例如获取响应代码或打开inputStream)之前,标头有效负载不会发送到服务器。

© www.soinside.com 2019 - 2024. All rights reserved.