我有以下代码:
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流量以确定实际发生的情况。