W3docs

Java HttpURLConnection

Make HTTP requests in Java with the legacy HttpURLConnection API.

HttpURLConnection is the HTTP-aware subclass of URLConnection. When you openConnection() on an http: or https: URL, the object you get back is an HttpURLConnection — cast it to reach the HTTP-specific features: setting the request method, reading the status code, and getting the separate error stream. It is the JDK's original HTTP client, available since Java 1.1.

This chapter covers casting the connection and choosing a method, sending a request body, the status code and the two response streams (the classic error-stream trap), and a full worked POST round trip you can run.

Modern note: for new code, prefer java.net.http.HttpClient — it is cleaner, supports HTTP/2, and handles async. HttpURLConnection is still everywhere in older codebases, so it is worth knowing well.

Casting and choosing a method

URL url = URI.create("http://example.com/api").toURL();
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("POST");                       // GET is the default
conn.setRequestProperty("Content-Type", "application/json");
conn.setConnectTimeout(2000);
conn.setReadTimeout(2000);

setRequestMethod takes "GET", "POST", "PUT", "DELETE", etc. Add request headers with setRequestProperty.

Sending a request body

To send a body you must opt in with setDoOutput(true) (which also makes the method default to POST), then write to the output stream:

conn.setDoOutput(true);
try (OutputStream os = conn.getOutputStream()) {
    os.write(payload.getBytes(StandardCharsets.UTF_8));
}

Status code and the two streams

The defining HTTP feature is the status code, and the trap that follows from it:

int code = conn.getResponseCode();          // triggers the request
InputStream body = (code >= 200 && code < 400)
        ? conn.getInputStream()             // success body
        : conn.getErrorStream();            // error body (4xx/5xx)

getInputStream() throws IOException on a 4xx/5xx response. The error body lives on a different stream, getErrorStream(). Forgetting this is the classic HttpURLConnection bug: an error response blows up instead of letting you read the server's explanation. Always branch on getResponseCode() first. Finish with conn.disconnect().

A worked example: a POST round trip

This program runs a loopback server that echoes the request body back with a 201 Created, then performs a POST through HttpURLConnection: setting the method, writing a body, reading the status, and choosing the right stream.

java— editable, runs on the server

What to take from the run:

  • Casting the URLConnection to HttpURLConnection unlocked the HTTP layer: setRequestMethod("POST"), getResponseCode(), and getResponseMessage() exist only on the subclass. For an http: URL the object really is an HttpURLConnection, so the cast always succeeds.
  • Sending a body required setDoOutput(true) before writing to getOutputStream(). Without that call the connection stays read-only and writing fails — opting into output is the switch that turns a GET into a body-carrying request.
  • getResponseCode() returned 201 and is what actually fired the request to the server. The status code is the first thing to read, because the next decision — which stream to read — depends on it.
  • The example branched between getInputStream() and getErrorStream(). Here 201 is success so the input stream carried the echoed body, but on a 4xx/5xx response getInputStream() would have thrown and the server's message would only be reachable through getErrorStream(). That split is the API's sharpest edge.
  • The flow took five-plus configuration calls for one POST, and disconnect() to clean up. That verbosity — manual streams, the error-stream trap, no built-in async — is exactly why HttpClient exists.

When to use HttpURLConnection

Reach for HttpURLConnection when you are on an older JDK (before Java 11), when a library or codebase already standardizes on it, or when you want to avoid pulling in any extra dependency for a single simple call. For anything new and non-trivial — connection reuse, HTTP/2, async, or cleaner request/response objects — prefer the modern HttpClient. If you only need to read from a URL without HTTP-specific control, the plain URL and URLConnection classes are enough.

Practice

Practice
A client does a PUT with 'HttpURLConnection'. When the server returns '400 Bad Request', the code crashes with an 'IOException' on 'conn.getInputStream()' instead of logging the server's error message. What is the correct fix?
A client does a PUT with 'HttpURLConnection'. When the server returns '400 Bad Request', the code crashes with an 'IOException' on 'conn.getInputStream()' instead of logging the server's error message. What is the correct fix?
Was this page helpful?