当已知代码时,HttpURLConnection.getResponseCode()会抛出IOException。

18

即使状态已知,为什么HttpURLConnection.getResponseCode()会抛出IOException异常?

Caused by: java.io.IOException: Server returned HTTP response code: 412 for URL: <my url>

获取响应代码并不是问题,因为它已经写在异常信息中了。

我希望有一种选项可以获取状态码(即使不是200),而不需要出现异常。这样我就能在我的代码中决定如何处理了。

完整的堆栈跟踪:

Caused by: java.io.IOException: Server returned HTTP response code: 412 for URL: <my url>
    at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1625)
    at java.net.HttpURLConnection.getResponseCode(HttpURLConnection.java:468)
... my code

更新 我更改了服务器端的实现,返回了一个不同的状态码(303),现在它工作正常(不会抛出IOException)。这意味着它特别与412有关。


1
什么意思?服务器正常工作,并按预期返回412。我希望能够在不抛出异常的情况下从连接中获取状态码。 - danieln
1
我无法回答为什么,但请考虑使用更复杂的HTTP客户端。 - Sotirios Delimanolis
2
你能展示完整的堆栈跟踪吗? - axtavt
@SotiriosDelimanolis,我不行。我正作为一个Java代理在工作。 - danieln
1
@Smutje 如果状态码是异常信息的一部分,这意味着连接能够获取状态码,那会怎样呢? - danieln
显示剩余5条评论
3个回答

8

注意:这可能取决于您正在运行的JVM版本!!! 正如@SotiriosDelimanolis的测试结果不同。

答案在HttpURLConnection的源代码中,并与所有具有错误代码> 400的错误相关。

如果错误代码等于404或410,则会抛出FileNotFoundException,否则会抛出IOException。

    if (respCode >= 400) {
        if (respCode == 404 || respCode == 410) {
            throw new FileNotFoundException(url.toString());
        } else {
            throw new java.io.IOException("Server returned HTTP" +
              " response code: " + respCode + " for URL: " +
              url.toString());
        }
    }

sun.net.www.protocol.http.HttpURLConnection源代码位于第1625行:

http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/7u40-b43/sun/net/www/protocol/http/HttpURLConnection.java#HttpURLConnection

我在Windows 64位操作系统上使用以下内容对http://media.jarnbjo.de/412.php进行测试:

Java(TM) SE Runtime Environment (build 1.7.0_21-b11) Java HotSpot(TM) 64-Bit Server VM (build 23.21-b01, mixed mode)

enter image description here


我们已经在之前的回答中检查过了,但那些回答已被删除。这不应该发生。你可以自己测试一下。 - Sotirios Delimanolis
这取决于您正在使用的SDK...这是来自OpenJDK 7。您在哪个JDK上进行测试的? - piacente.cristian
这不是我要告诉你的。使用 HttpURLConnection 向 http://media.jarnbjo.de/412.php 发送 HTTP GET 请求。您将不会收到异常,而会收到 412 状态码。 - Sotirios Delimanolis
@SotiriosDelimanolis 我更新了答案并加入了细节,就像我之前所说的,这取决于你的JVM :) - piacente.cristian
1
请注意您使用了 getInputStream() 而不是 getResponseCode()。OP 的错误在于 getResponseCode() - Sotirios Delimanolis
显示剩余2条评论

8
今天在工作中我遇到了同样的问题 - 我们的代码调用了HttpURLConnection.getResponseCode(),结果出现了Caused by: java.io.IOException: Server returned HTTP response code: 400 for URL: ...。经过一番深入研究JDK源代码后,我发现以下几点:
  • getResponseCode() 实际上并没有抛出异常!
  • 来自 getResponseCode() 深处会抛出一个异常,但它被捕获了。
    • 在它被捕获之前,一些字段在 HttpURLConnection 中得到设置,使得 getResponseCode() 成功地执行。
    • 同样在它被捕获之前,该异常被保存到 HttpURLConnection 的一个子类的字段中(具体来说是: sun.net.www.protocol.http.HttpURLConnection.rememberedException)。
  • 随后,我们的代码直接调用了 getInputStream(),这种情况下应该会抛出异常。(你应该调用 getErrorStream()。)
  • getInputStream() 抛出的异常包装了原始的抛出和捕获的异常。
  • 因此,即使我们实际的问题出现在我们直接调用 getInputStream() 的代码行中,我们最终得到的堆栈跟踪仍然会在我们调用 getResponseCode() 的代码行中引用到Caused by
    • 堆栈跟踪也提到了稍后的那一行代码,但我起初没有注意到。
我打赌你遇到的问题也是这样的。

0

这些其他回答似乎忽略了一点,在我的JDK上,getResponseCode()并不会抛出异常,但它看起来确实会抛出异常。

实际发生的事情是,我调用了getResponseCode()(它没有抛出异常),然后我调用了connection.getInputStream()

connection.getInputStream()确实会抛出异常,这是规范要求的,但它将你调用getResponseCode()的异常堆栈作为“cause”添加进去了。也就是说,如果你查看堆栈跟踪,它看起来像这样:

...
    ... 20 common frames omitted
Caused by: java.io.IOException: Server returned HTTP response code: 400 for URL: http://localhost:8080/system
    at java.base/sun.net.www.protocol.http.HttpURLConnection.getInputStream0(HttpURLConnection.java:1924)
    at java.base/sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1520)
    at java.base/java.net.HttpURLConnection.getResponseCode(HttpURLConnection.java:527)
    at yourpackage.yourcode.**YourClass.yourMethod**([line number where you invoked getResponseCode()]
    ... 22 common frames omitted

所以,就像我说的那样,getResponseCode()并不会抛出异常,但看起来确实是会抛出异常的。注意。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接