概要
HttpURLConnection は Java 1.1 から存在する HTTP 通信の標準 API です。Java 11 以降では HttpClient が推奨されますが、Java 8 環境の保守案件や、外部ライブラリを追加できない制約のあるプロジェクトでは今でも現役で使われています。ただし、ストリームの読み書きやエラーレスポンスの扱い、disconnect のタイミングなど、初見で引っかかるポイントが多い API でもあります。この記事では、GET/POST の基本パターンから、エラーストリームの正しい読み取り方、タイムアウト設定、レスポンスヘッダーの取得まで、実務で困らないレベルの知識を整理します。Java 21 では sealed interface で成功/失敗を型安全に表現するパターンも紹介します。
使いどころ
Java 8 環境の保守案件で外部 API にリクエストを送信する
外部ライブラリの追加が制限された環境で HTTP 通信を実装する
テスト環境で簡易的な HTTP リクエストを送信してエンドポイントの疎通確認を行う
コード例
import java.io.BufferedReader;
public class HttpURLConnectionSample {
private static final int CONNECT_TIMEOUT_MS = 5000;
private static final int READ_TIMEOUT_MS = 10000;
public static String get(String urlStr) throws IOException {
var conn = (HttpURLConnection) new URL(urlStr).openConnection();
try {
conn.setRequestMethod("GET");
conn.setConnectTimeout(CONNECT_TIMEOUT_MS);
conn.setReadTimeout(READ_TIMEOUT_MS);
conn.setRequestProperty("Accept", "application/json");
var status = conn.getResponseCode();
if (status >= 400) {
try (var br = new BufferedReader(
new InputStreamReader(conn.getErrorStream(), StandardCharsets.UTF_8))) {
throw new IOException("HTTP エラー " + status + ": " + readAll(br));
}
}
try (var br = new BufferedReader(
new InputStreamReader(conn.getInputStream(), StandardCharsets.UTF_8))) {
return readAll(br);
}
} finally {
conn.disconnect();
}
}
public static String post(String urlStr, String jsonBody) throws IOException {
var conn = (HttpURLConnection) new URL(urlStr).openConnection();
try {
conn.setRequestMethod("POST");
conn.setConnectTimeout(CONNECT_TIMEOUT_MS);
conn.setReadTimeout(READ_TIMEOUT_MS);
conn.setDoOutput(true);
conn.setRequestProperty("Content-Type", "application/json; charset=UTF-8");
var bodyBytes = jsonBody.getBytes(StandardCharsets.UTF_8);
conn.setRequestProperty("Content-Length", String.valueOf(bodyBytes.length));
try (OutputStream os = conn.getOutputStream()) {
os.write(bodyBytes);
}
var status = conn.getResponseCode();
if (status >= 400) {
try (var br = new BufferedReader(
new InputStreamReader(conn.getErrorStream(), StandardCharsets.UTF_8))) {
throw new IOException("HTTP エラー " + status + ": " + readAll(br));
}
}
try (var br = new BufferedReader(
new InputStreamReader(conn.getInputStream(), StandardCharsets.UTF_8))) {
return readAll(br);
}
} finally {
conn.disconnect();
}
}
private static String readAll(BufferedReader br) throws IOException {
var sb = new StringBuilder();
String line;
while ((line = br.readLine()) != null) {
sb.append(line);
}
return sb.toString();
}
public static void main(String[] args) throws IOException {
String response = get("https://httpbin.org/get");
System.out.println(response);
}
}Version Coverage
var(JEP 286)による型推論で HttpURLConnection の型宣言を省略でき、記述が簡潔になる。エラーストリームの処理パターンも整理しやすい。
// Java 17: var で簡潔に
var conn = (HttpURLConnection)
new URL(urlStr).openConnection();
try {
conn.setRequestMethod("GET");
var status = conn.getResponseCode();
if (status >= 400) {
try (var br = new BufferedReader(
new InputStreamReader(
conn.getErrorStream()))) {
throw new IOException(readAll(br));
}
}
} finally {
conn.disconnect();
}Library Comparison
注意点
getErrorStream() は 4xx/5xx のときだけ非 null を返す。getInputStream() をそのまま呼ぶと IOException が発生する
disconnect() を finally ブロックで必ず呼ぶこと。呼ばないとソケットが解放されずリソースリークになる
setDoOutput(true) を呼ばないと POST のリクエストボディを送信できない。GET の場合は false(デフォルト)のままにする
URL クラスのコンストラクタは Java 20 で非推奨になった。将来的には URI.create().toURL() への移行が必要
FAQ
API 自体は非推奨ではありません。ただし Java 11 以降の新規プロジェクトでは HttpClient が推奨です。Java 8 環境や保守案件では引き続き使用できます。
HttpURLConnection.setFollowRedirects(true) でデフォルトで有効です。ただし HTTP から HTTPS へのリダイレクトは自動追跡されないため、手動でリダイレクト先 URL を取得して再接続する必要があります。
ステータスコードが 400 以上の場合、getInputStream() ではなく getErrorStream() からレスポンスボディを読みます。null チェックも忘れずに行ってください。