执行请求后,我想检查请求标头,但是它不起作用。
我在getRequestProperties()
实例上调用sun.net.www.protocol.http.HttpURLConnection
,并且始终收到带有消息“Already connect”的IllegalStateException。好像我想设置请求属性。但是我只想阅读它们。
负责此行为的代码在HttpUrlConnection中:
http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/7u40-b43/sun/net/www/protocol/http/HttpURLConnection.java#HttpURLConnection.getRequestProperties%28%29
public synchronized Map<String, List<String>> getRequestProperties() {
if (connected)
throw new IllegalStateException("Already connected");
// ...
}
好的,也许我应该仅在断开连接后读取请求属性。但事实证明,
disconnect()
并未将connected
设置为false
。虽然应该:http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/7u40-b43/sun/net/www/protocol/http/HttpURLConnection.java#HttpURLConnection.disconnect%28%29无论我是否读完流,这似乎也没有什么不同。在调用断开连接之前或之后关闭InputStream也不会有任何不同。
我很困惑。你能帮助我吗?
disconnect()
设置为false? 重现此代码是针对Android的单元测试(我使用Robolectric),但我认为您也可以在Java项目中使用它,并在删除测试注释后从main()调用它:
/**
* Test if HttpUrlConnection works as expected, because in some cases it seems it doesn't
*
* @throws Exception
*/
@Test
public void testHttpUrlConnection() throws Exception
{
final URL url = new URL("http://www.stackoverflow.com");
final HttpURLConnection urlConnection = ( HttpURLConnection ) url.openConnection( );
urlConnection.setRequestMethod("GET");
InputStream is = null;
try
{
is = urlConnection.getInputStream();
assertEquals(200, urlConnection.getResponseCode());
}
catch (IOException ex)
{
is = urlConnection.getErrorStream( );
}
final String result = copyStreamToString(is); // some html response
// Streams must be closed before disconnecting (according to http://stackoverflow.com/a/11056207/3596676)
is.close();
assertTrue((Boolean) getFieldViaRecursiveReflection(urlConnection, "connected"));
// urlConnection should always be disconnected (according to http://developer.android.com/reference/java/net/HttpURLConnection.html)
urlConnection.disconnect();
assertFalse((Boolean) getFieldViaRecursiveReflection(urlConnection, "connected")); // AssertionError
// getRequestProperties throws IllegalStateException ("already connected")
Map<String, List<String>> requestProperties = urlConnection.getRequestProperties();
// do stuff with the properties
// return the result
}
private static String copyStreamToString( final InputStream is ) throws IOException
{
if ( is == null )
{
return "";
}
BufferedReader reader = new BufferedReader( new InputStreamReader( is ) );
String result = copyBufferedReaderToString( reader );
reader.close( );
return result;
}
private static String copyBufferedReaderToString( final BufferedReader bufferedReader ) throws IOException
{
StringBuffer sb = new StringBuffer( );
String line;
while ( ( line = bufferedReader.readLine( ) ) != null )
{
sb.append( line );
}
return sb.toString( );
}
private static Object getFieldViaRecursiveReflection(final Object object, final String attribute) throws Exception
{
return getFieldViaRecursiveReflection(object, object.getClass(), attribute);
}
private static Object getFieldViaRecursiveReflection(final Object object, final Class<?> c, final String attribute) throws Exception
{
try
{
final Field field = c.getDeclaredField(attribute);
field.setAccessible(true);
return field.get(object);
}
catch (NoSuchFieldException ex)
{
/* end of type hierarchy? */
Class<?> superClass = c.getSuperclass();
if (superClass == null)
{
throw ex;
}
else
{
return getFieldViaRecursiveReflection(object, superClass, attribute);
}
}
}
最佳答案
自从我提出问题以来的两个月内,没有人发布答案,但是今天我不得不再次解决该问题并找到解决方案,我将回答我自己的问题。
我无法回答答案中的所有问题(例如“为什么urlConnection.disconnect()
不将connected
的urlConnection
属性设置为false
吗?”),但我找到了主要问题的解决方案,即读取请求的标头连接urlConnection时不起作用。
由于某种原因(我不记得了),我希望/需要在请求完成并且响应在那里之后检查请求标头。但是我再次查看了getRequestProperties()
中sun.net.www.protocol.http.HttpURLConnection
的实现(请参见代码here),并注意到调用了一种称为filterAndAddHeaders
的方法。因此,似乎不仅可以在该方法中读取标头,还可以对其进行设置。我不确定为什么要使用getter方法(即getRequestProperties()
一个)完成此操作,但是有意义的是,当请求已完成时,当用户尝试添加请求标头时应警告用户-在这种情况下使用IllegalStateException
令我非常困扰。
得出解决方案:
在发送请求之前,我只是将对getRequestProperties()
的调用移至。现在一切正常。
附言:
请注意,这还不是全部。即使我在请求后调用getRequestProperties()
,我的单元测试之一仍成功运行。在这种情况下,urlConnection
内部属性connected
设置为false。我还没有弄清楚,但是它可能与响应状态代码304(未修改)有关。如果您必须处理此问题,并且由于某种原因在发送请求之前无法将getRequestProperties()
调用移至,这可能会有所提示。