异常后使用java http连接实例

时间:2014-01-22 15:18:56

标签: java httpurlconnection urlconnection httpsurlconnection

以下代码是否安全:

try {
    URL url = new URL(urlRequest);
    conn = (HttpURLConnection)url.openConnection();
    conn.setConnectTimeout(30000);
    conn.setReadTimeout(30000);
    conn.setRequestProperty("Accept-Encoding", "gzip, deflate");
    String encoding = conn.getContentEncoding();
    return Utils.wrapCompressedStream(conn.getInputStream(), encoding);
} catch (IOException e) {
    if(conn != null) {
        conn.getContentEncoding();
        conn.getErrorStream();
        conn.whateverOtherMethodThere();
        ...
    }
}

特别是,在InterruptedIOException(例如,读取超时)调用getContentEncoding()之类的方法时是否安全?据我所知,此方法需要实时连接才能读取HTTP(S)标头。

更新(附加信息):

这个问题源于真实的系统体验。我相信,系统是在Oracle / Sun JVM 1.6上运行的。代码几乎相同:

...    
} catch (IOException e) {
    if(conn != null) {
         try {
             String response = tryGetResponse(conn);
...

问题发生在 HTTPS 请求的tryGetResponse

 private static String tryGetResponse(HttpURLConnection conn) {
    if(conn == null) return "(failed to get)";
    InputStream in = null;
    try {
        InputStream err = conn.getErrorStream();
        if (err != null) {
            in = Utils.wrapCompressedStream(err, conn.getContentEncoding());
        }
        return Utils.inputStreamToString(in);
    } catch (IOException e) {
        return "(failed to get)";
    } finally {
        Utils.closeQuitely(in);
    }
}

自发系统挂在getContentEncoding()电话的套接字连接(或读取)上:

in = Utils.wrapCompressedStream(err, conn.getContentEncoding());

在初始代码中抛出SocketTimeoutException之后。

因此,似乎getContentEncoding()尝试(或在Java 6中尝试)建立新连接而不设置超时。

4 个答案:

答案 0 :(得分:3)

没有。一般来说不安全。 JVM实现(认为IBM J9与Oracle VM与Open JDK之间)的行为可能不同,并且在不通知的情况下在同一VM的版本之间进行更改。

原因是API规范不做任何保证。

如果您告诉我您使用哪个特定版本的具体实现,我可以查看来源并尝试做出一些结论。但我强烈建议不要依赖你在那里找到的行为。

关于HTTP S :SSL似乎仍然存在一些漏洞。例如,OpenSSL已经发布了public announcement,他们将在本周末发布一个安全漏洞。修复此错误可能会在某些错误情况下更改HTTPS连接的行为。可能的是,无论我们在消息来源中找到什么,都会在本周末没有实际意义。如果没有,它可能会随着下一个安全修复程序而改变。

更新:

我已经尝试找到与您在更新的问题中引用的Java版本相对应的源代码。查找Java-Sources不是一个大问题,但代码很快就会进入本机部分。仅此一点就是一个很好的暗示,答案不仅仅是版本特定的,还有平台特定的(Linux,Windows,Mac等)。您可以查看Java 1.6的OpenJDK源代码,例如: for the network stack for Windows

注意:您很可能使用过Sun JDK 1.6。 OpenJDK 1.6在Sun / Oracle JDK上,但在JDK 1.7上。 Open JDK 1.6是Sun / Oracle JDK 1.7 backportet到Java 1.6的代码形式。所以仍然可能存在一些小的差异,但在发生错误后对连接的使用仍然很重要。

答案 1 :(得分:2)

对于getErrorStream spec说:

  

如果连接失败但服务器仍然发送了有用的数据,则返回错误流。典型示例是当HTTP服务器以404响应时,这将导致在连接中抛出FileNotFoundException,但服务器发送了一个HTML帮助页面,其中包含有关如何操作的建议。   此方法不会导致启动连接。如果未连接连接,或者连接时服务器没有错误,或者服务器出现错误但未发送错误数据,则此方法将返回null。这是默认值。

     

返回:   错误流(如果有),如果没有错误,则为null,连接未连接或服务器未发送任何有用数据。

您还可以检查source以消除疑虑,让我们看一些方法:

public InputStream getErrorStream() {
    if (connected && responseCode >= 400) {
        // Client Error 4xx and Server Error 5xx
        if (errorStream != null) {
            return errorStream;
        } else if (inputStream != null) {
            return inputStream;
        }
    }
    return null;
}

可以安全地调用它(不会抛出任何异常),并且可以在某些errorStream个案例中设置IOException。来源中的评论为buffer the error stream if bytes < 4k and it can be buffered within 1 second

getContentEncoding来自规范的行为是:

  

返回:   URL引用的资源的内容编码,如果不知道则为null。

但是错误之后怎么办?让我们看看代码:

public String getContentEncoding() { //from the base class java.net.URLConnection
    return getHeaderField("content-encoding");
}

public String getHeaderField(String name) {
    try {
        getInputStream();
    } catch (IOException e) {} //ah exception is eaten

    if (cachedHeaders != null) {
        return cachedHeaders.findValue(name);
    }

    return responses.findValue(name);
}

因此,如果已知,它会缓存标头并返回它们,即使可能在IOException之后,它也不会传播异常,但如果以前没有成功获得标头,则可能返回null。

答案 2 :(得分:2)

  

特别是,InterruptedIOException(例如,读取超时)调用getContentEncoding()?

等方法是否安全?

你可以试试。最糟糕的情况是另一个IOException.IOException,例如FileNotFoundException,的几种情况下,调用getErrorStream()并读取错误页面的内容是完全安全的。

答案 3 :(得分:0)

catch (IOException e) {
    if(conn != null) {
        conn.getContentEncoding();
        conn.getErrorStream();
        conn.whateverOtherMethodThere();
        ...
    }

公共类InterruptedIOException 扩展IOException

  

表示I / O操作已中断。抛出InterruptedIOException以指示输入或输出传输已终止,因为执行它的线程已中断。 bytesTransferred字段表示在中断发生之前成功传输了多少字节。

这意味着如果发生中断的异常,则无法对HttpUrlConnection进行进一步处理。

再次通过IOException,您无法捕获其他类型的异常,例如IllegalArgumentException,illegalthreadstate异常等等。

有关详细信息http://download.java.net/jdk7/archive/b123/docs/api/java/net/HttpURLConnection.html#getRequestMethod%28%29