HttpURLConnection.getRequestProperties()抛出IllegalStateException:"已经连接"

bac*_*dev 4 java android httpurlconnection

执行请求后,我想检查请求标头,但它不起作用.

我调用getRequestProperties()了一个实例,sun.net.www.protocol.http.HttpURLConnection我总是得到一个带有"已经连接"消息的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");
    // ...
}
Run Code Online (Sandbox Code Playgroud)

好的,也许我应该只在断开连接后读取请求属性.但事实证明,disconnect()不设置connectedfalse.虽然它应该:http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/7u40-b43/sun/net/www/protocol/http/HttpURLConnection.java#HttpURLConnection.disconnect% 28%29

如果我将流读到最后,它似乎也没有什么区别.在调用disconnect之前或之后关闭InputStream也没有什么区别.

我糊涂了.你能帮助我吗?

  1. 为什么不disconnect()设置连接到false?
  2. 为什么我在连接urlConnection时无法读取请求属性?
  3. 如何在请求后正确读取请求标头?

重现这个的代码是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);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

bac*_*dev 6

自从我提出问题以来的2个月里没有人发布答案,但今天我不得不再次处理问题并找到解决方案,我将回答我自己的问题.

我不能回答的回答所有的问题(例如,"为何不urlConnection.disconnect()设定connected的属性urlConnectionfalse?"),但我发现的主要问题的解决方案,这是读请求的头不工作当urlConnection连接时.

由于某些原因,我不记得了,我希望/需要在请求完成后检查请求标头并且响应在那里.但是我再次查看了getRequestProperties()in 的实现sun.net.www.protocol.http.HttpURLConnection(参见此处的代码)并注意到一个名为filterAndAddHeadersgets 的方法被调用.因此,标题不仅可以在该方法中读取,而且可以设置.我不确定为什么这是在getter方法(getRequestProperties()一个)中完成的,但是当请求已经完成时,你应该在用户尝试添加请求标头时警告用户 - 在这种情况下IllegalStateException是打扰的我这么多.

来解决方案:

我只是在请求发送之前将呼叫转移getRequestProperties()到了.现在一切正常.

PS:

请注意,这不是全部.即使我getRequestProperties()在请求后打电话,我的一个单元测试也成功运行.在这种情况下,urlConnection内部属性connected设置为false.我没有想到这一切,但它可能与响应状态代码304(未修改)有关.如果您必须处理此问题并且出于某种原因无法getRequestProperties()在发送请求之前移动呼叫,这可能有助于提示.