HttpURLConnection.getResponseCode() throws IOException when code is known
ATTENTION: this may depend on the JVM version you are running!!! as tests of @SotiriosDelimanolis gave different results
The answer is in the source code of the HttpURLConnection and is related to all the errors that have error code > 400
If error code is equal 404 or 410 a FileNotFoundException is thrown else an IOException as
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 Source code at line 1625:
http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/7u40-b43/sun/net/www/protocol/http/HttpURLConnection.java#HttpURLConnection
My test on http://media.jarnbjo.de/412.php using :
Java(TM) SE Runtime Environment (build 1.7.0_21-b11) Java HotSpot(TM) 64-Bit Server VM (build 23.21-b01, mixed mode)
on Windows 64 bit
I encountered the same problem today at work — our code was calling HttpURLConnection.getResponseCode()
and ending up with Caused by: java.io.IOException: Server returned HTTP response code: 400 for URL: ...
— and after some quality time diving through the JDK source code, I ended up figuring out the following:
getResponseCode()
isn't actually throwing an exception!- An exception gets thrown from deep inside
getResponseCode()
, but it gets caught.- Before it's caught, some fields get set inside
HttpURLConnection
that allowgetResponseCode()
to succeed, which it does. - Also before it's caught, the exception gets saved to a field in a subclass of
HttpURLConnection
(specifically:sun.net.www.protocol.http.HttpURLConnection.rememberedException
).
- Before it's caught, some fields get set inside
- Subsequently, our code called
getInputStream()
directly, which is supposed to throw an exception in this case. (You're supposed to callgetErrorStream()
instead.) getInputStream()
throws an exception that wraps the original thrown-and-caught exception.- So we ended up getting a stacktrace with
Caused by
-s that referred to our line of code where we were callinggetResponseCode()
, even though our actual issue was later, in our line of code where we were callinggetInputStream()
directly.- The stacktrace also mentions that later line of code, but I didn't notice that at first.
I'm betting that your case was the same.