Apache HttpClient 5.xをマスターする!基本から応用まで徹底解説

この記事から得られる知識

  • Apache HttpClientの基本的な使い方(GET、POSTリクエスト)を理解できる。
  • タイムアウト設定やコネクションプーリングなど、パフォーマンスチューニングに不可欠な設定方法を習得できる。
  • ファイルアップロードやJSONデータの送信など、実践的なリクエストの作成方法がわかる。
  • 非同期リクエストの処理方法を学び、スケーラブルなアプリケーション開発に応用できる。
  • SSL/TLS通信や認証など、セキュリティ関連の高度な設定について理解を深めることができる。

はじめに:なぜApache HttpClientなのか?

現代のJavaアプリケーション開発において、外部のAPIやWebサービスとの連携は不可欠です。Javaには標準で `java.net.HttpURLConnection` が用意されていますが、より高度で柔軟なHTTP通信を実装するには機能不足を感じる場面が少なくありません。

そこで登場するのが、Apache HttpClient です。これは、Apache Software Foundationが提供する非常に高機能で堅牢なHTTPクライアントライブラリです。きめ細やかな設定、接続管理、認証、クッキー管理など、エンタープライズレベルのアプリケーション開発に求められる多くの機能を備えています。

特に、HttpClient 5.x系では、非同期処理のサポートが大幅に強化され、モダンなアプリケーション開発の要求に応える進化を遂げています。この記事では、HttpClient 5.xに焦点を当て、基本的な使い方から応用的なテクニックまでを、豊富なコード例と共に徹底的に解説します。

第1章: 準備と基本的な使い方

まずは、HttpClientを利用するための準備と、最も基本となるGETリクエストの送信方法について学びます。

1.1. Maven/Gradleへの依存関係の追加

HttpClientを利用するために、プロジェクトのビルドファイルに以下の依存関係を追加します。ここでは、広く使われているMavenとGradleの例を示します。

Maven (pom.xml)

<!-- HttpClient 5のコアライブラリ -->
<dependency> <groupId>org.apache.httpcomponents.client5</groupId> <artifactId>httpclient5</artifactId> <version>5.5</version> <!-- 2025年5月時点の最新安定版 -->
</dependency>
<!-- Fluent APIを利用する場合(オプション) -->
<dependency> <groupId>org.apache.httpcomponents.client5</groupId> <artifactId>httpclient5-fluent</artifactId> <version>5.5</version>
</dependency>

最新のバージョンはMaven Centralで確認してください。

1.2. 基本的なGETリクエスト

依存関係を追加したら、早速GETリクエストを送信してみましょう。HttpClient 5.xでは、`CloseableHttpClient` を使用し、リソースの解放を確実に行うために try-with-resources文 を使うことが強く推奨されています。

以下の例では、`HttpClients.createDefault()` を使ってデフォルト設定のクライアントインスタンスを生成し、指定したURLへGETリクエストを送信します。

import org.apache.hc.client5.http.classic.methods.HttpGet;
import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
import org.apache.hc.client5.http.impl.classic.HttpClients;
import org.apache.hc.core5.http.HttpEntity;
import org.apache.hc.core5.http.io.entity.EntityUtils;
public class SimpleGetRequest { public static void main(String[] args) { // try-with-resources文でHttpClientを生成 try (CloseableHttpClient httpClient = HttpClients.createDefault()) { HttpGet httpGet = new HttpGet("https://httpbin.org/get"); System.out.println("Executing request " + httpGet.getMethod() + " " + httpGet.getUri()); // レスポンスハンドラを使用してレスポンスを処理 String responseBody = httpClient.execute(httpGet, response -> { System.out.println("----------------------------------------"); System.out.println(response.getCode() + " " + response.getReasonPhrase()); // ステータスコードが200番台かチェック if (response.getCode() < 200 || response.getCode() >= 300) { throw new RuntimeException("Failed : HTTP error code : " + response.getCode()); } HttpEntity entity = response.getEntity(); return entity != null ? EntityUtils.toString(entity) : null; }); System.out.println("----------------------------------------"); System.out.println("Response body:"); System.out.println(responseBody); } catch (Exception e) { e.printStackTrace(); } }
}

リソース管理の重要性

HttpClient 4.xまでは `CloseableHttpResponse` を手動で `close()` する必要がありましたが、HttpClient 5.xでは上記のようにレスポンスハンドラ(ラムダ式)を使うことで、リソース管理がより簡潔かつ安全になりました。ハンドラの処理が終了すると、レスポンスと接続が自動的に解放されます。

第2章: POSTリクエストとエンティティ

データをサーバーに送信する際に使用されるPOSTリクエストの作成方法を見ていきます。HttpClientでは、送信するデータの内容に応じて様々な `HttpEntity` の実装を使い分けます。

2.1. フォームデータの送信 (`UrlEncodedFormEntity`)

HTMLのフォームのような `key=value` 形式のデータを送信する場合は `UrlEncodedFormEntity` を使用します。

import org.apache.hc.client5.http.classic.methods.HttpPost;
import org.apache.hc.client5.http.entity.UrlEncodedFormEntity;
import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
import org.apache.hc.client5.http.impl.classic.HttpClients;
import org.apache.hc.core5.http.HttpEntity;
import org.apache.hc.core5.http.NameValuePair;
import org.apache.hc.core5.http.io.entity.EntityUtils;
import org.apache.hc.core5.http.message.BasicNameValuePair;
import java.util.ArrayList;
import java.util.List;
public class PostFormRequest { public static void main(String[] args) { try (CloseableHttpClient httpClient = HttpClients.createDefault()) { HttpPost httpPost = new HttpPost("https://httpbin.org/post"); // パラメータリストを作成 List<NameValuePair> params = new ArrayList<>(); params.add(new BasicNameValuePair("username", "myuser")); params.add(new BasicNameValuePair("password", "mypassword")); // エンティティとして設定 httpPost.setEntity(new UrlEncodedFormEntity(params)); String responseBody = httpClient.execute(httpPost, response -> { // ... レスポンス処理 (GETの例と同様) HttpEntity entity = response.getEntity(); return EntityUtils.toString(entity); }); System.out.println(responseBody); } catch (Exception e) { e.printStackTrace(); } }
}

2.2. JSONデータの送信 (`StringEntity`)

REST APIなどで一般的に使用されるJSON形式のデータを送信するには `StringEntity` を使用します。このとき、`Content-Type` ヘッダーを `application/json` に設定することが重要です。

import org.apache.hc.client5.http.classic.methods.HttpPost;
import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
import org.apache.hc.client5.http.impl.classic.HttpClients;
import org.apache.hc.core5.http.ContentType;
import org.apache.hc.core5.http.HttpEntity;
import org.apache.hc.core5.http.io.entity.EntityUtils;
import org.apache.hc.core5.http.io.entity.StringEntity;
public class PostJsonRequest { public static void main(String[] args) { try (CloseableHttpClient httpClient = HttpClients.createDefault()) { HttpPost httpPost = new HttpPost("https://httpbin.org/post"); // 送信するJSON文字列 String json = "{\"id\":1, \"name\":\"Taro Yamada\", \"email\":\"taro.yamada@example.com\"}"; // StringEntityを作成 StringEntity stringEntity = new StringEntity(json, ContentType.APPLICATION_JSON); httpPost.setEntity(stringEntity); // Content-Typeヘッダーを明示的に設定することも可能 // httpPost.setHeader("Content-Type", "application/json"); String responseBody = httpClient.execute(httpPost, response -> { // ... レスポンス処理 HttpEntity entity = response.getEntity(); return EntityUtils.toString(entity); }); System.out.println(responseBody); } catch (Exception e) { e.printStackTrace(); } }
}

2.3. ファイルアップロード (`MultipartEntityBuilder`)

ファイルと他のテキストデータを同時に送信する、いわゆるマルチパートリクエストには `MultipartEntityBuilder` を使用します。これにより、複雑なマルチパートボディを簡単に構築できます。

import org.apache.hc.client5.http.classic.methods.HttpPost;
import org.apache.hc.client5.http.entity.mime.MultipartEntityBuilder;
import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
import org.apache.hc.client5.http.impl.classic.HttpClients;
import org.apache.hc.core5.http.ContentType;
import org.apache.hc.core5.http.HttpEntity;
import org.apache.hc.core5.http.io.entity.EntityUtils;
import java.io.File;
import java.nio.charset.StandardCharsets;
public class FileUploadRequest { public static void main(String[] args) { try (CloseableHttpClient httpClient = HttpClients.createDefault()) { HttpPost httpPost = new HttpPost("https://httpbin.org/post"); // アップロードするファイル File file = new File("path/to/your/file.txt"); // MultipartEntityBuilderを使ってボディを構築 HttpEntity multipartEntity = MultipartEntityBuilder.create() .setCharset(StandardCharsets.UTF_8) // 日本語ファイル名などの文字化け対策 .addBinaryBody("file", file, ContentType.APPLICATION_OCTET_STREAM, file.getName()) .addTextBody("comment", "This is a test file.", ContentType.TEXT_PLAIN) .build(); httpPost.setEntity(multipartEntity); String responseBody = httpClient.execute(httpPost, response -> { // ... レスポンス処理 HttpEntity entity = response.getEntity(); return EntityUtils.toString(entity); }); System.out.println(responseBody); } catch (Exception e) { e.printStackTrace(); } }
}
`MultipartEntityBuilder`は、テキストパート (`addTextBody`) やバイナリパート (`addBinaryBody`) を柔軟に追加できるため、様々な形式のマルチパートリクエストに対応可能です。

第3章: HttpClientの高度な設定

実運用では、タイムアウトやプロキシなど、より詳細な設定が必要になります。これらの設定は `RequestConfig` を使って行います。

3.1. タイムアウト設定 (`RequestConfig`)

ネットワークの問題などでリクエストが永遠に待ち続けることを防ぐため、タイムアウト設定は非常に重要です。HttpClient 5では、主に以下の3つのタイムアウトを設定します。

タイムアウトの種類説明設定メソッド
コネクションタイムアウトターゲットホストとの接続が確立されるまでの最大時間。`setConnectTimeout` (in `ConnectionConfig`)
レスポンスタイムアウト接続が確立されてから、レスポンスデータが返却されるまでの最大時間。`setResponseTimeout` (in `RequestConfig`)
コネクションリクエストタイムアウトコネクションマネージャのプールから接続が取得できるまでの最大待機時間。`setConnectionRequestTimeout` (in `RequestConfig`)

HttpClient 5.x系では、タイムアウトの単位を `java.util.concurrent.TimeUnit` や `org.apache.hc.core5.util.Timeout` クラスで明示的に指定します。`setConnectTimeout`は `RequestConfig` では非推奨となり、後述するコネクションマネージャの `ConnectionConfig` で設定することが推奨されています。

import org.apache.hc.client5.http.config.RequestConfig;
import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
import org.apache.hc.client5.http.impl.classic.HttpClientBuilder;
import org.apache.hc.core5.util.Timeout;
import java.util.concurrent.TimeUnit;
public class TimeoutConfig { public static void main(String[] args) { // RequestConfigでタイムアウトを設定 RequestConfig requestConfig = RequestConfig.custom() .setConnectionRequestTimeout(Timeout.ofSeconds(5)) // コネクションプールからの取得タイムアウト .setResponseTimeout(Timeout.ofSeconds(10)) // レスポンスタイムアウト .build(); // HttpClientをビルドする際にデフォルト設定として適用 try (CloseableHttpClient httpClient = HttpClientBuilder.create() .setDefaultRequestConfig(requestConfig) .build()) { // このhttpClientを使ったリクエストはすべて上記の設定が適用される // ... リクエスト実行処理 ... } catch (Exception e) { e.printStackTrace(); } }
}

3.2. プロキシ設定

社内ネットワークなど、プロキシサーバー経由で外部に接続する必要がある場合は、`HttpHost`オブジェクトでプロキシ情報を定義し、`RequestConfig` に設定します。

import org.apache.hc.client5.http.config.RequestConfig;
import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
import org.apache.hc.client5.http.impl.classic.HttpClientBuilder;
import org.apache.hc.core5.http.HttpHost;
public class ProxyConfig { public static void main(String[] args) { // プロキシサーバーの情報を設定 HttpHost proxy = new HttpHost("http", "your.proxy.host", 8080); RequestConfig requestConfig = RequestConfig.custom() .setProxy(proxy) .build(); try (CloseableHttpClient httpClient = HttpClientBuilder.create() .setDefaultRequestConfig(requestConfig) .build()) { // ... リクエスト実行処理 ... } catch (Exception e) { e.printStackTrace(); } }
}

第4章: コネクション管理とプーリング

HTTPリクエストを頻繁に送信するアプリケーションでは、リクエストごとにTCP接続を確立するのは非効率です。そこで、確立した接続を再利用する「コネクションプーリング」がパフォーマンス向上の鍵となります。

HttpClientでは `PoolingHttpClientConnectionManager` を使用してコネクションプーリングを実装します。

4.1. `PoolingHttpClientConnectionManager` の設定

コネクションプーリングを利用するには、`HttpClientBuilder` に `PoolingHttpClientConnectionManager` のインスタンスを設定します。

import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
import org.apache.hc.client5.http.impl.classic.HttpClientBuilder;
import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManager;
import org.apache.hc.core5.http.io.SocketConfig;
import org.apache.hc.core5.util.Timeout;
public class ConnectionPooling { public static void main(String[] args) { // コネクションマネージャの作成と設定 PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager(); // プール全体の最大接続数を設定 connManager.setMaxTotal(200); // ルート(ホスト)ごとの最大接続数を設定 connManager.setDefaultMaxPerRoute(20); // ソケット設定(接続タイムアウトはこちらで設定) SocketConfig socketConfig = SocketConfig.custom() .setSoTimeout(Timeout.ofSeconds(5)) // ソケットタイムアウト(データの読み取りタイムアウト) .build(); connManager.setDefaultSocketConfig(socketConfig); // HttpClientの生成 try (CloseableHttpClient httpClient = HttpClientBuilder.create() .setConnectionManager(connManager) .build()) { // このhttpClientはコネクションプーリングを利用して効率的にリクエストを処理する // 複数のスレッドからこのhttpClientを安全に共有できる // ... 多数のリクエストを並行して実行 ... } catch (Exception e) { e.printStackTrace(); } }
}

パフォーマンスのヒント

`setMaxTotal` と `setDefaultMaxPerRoute` の値は、アプリケーションの特性(秒間リクエスト数、接続先ホスト数など)に合わせてチューニングすることが重要です。デフォルト値はそれぞれ20と2であり、多くの実アプリケーションでは小さすぎる可能性があります。

第5章: 認証とセキュリティ

APIによっては認証が必要であったり、自己署名証明書など特殊なSSL/TLS設定が必要な場合があります。

5.1. Basic認証

Basic認証が必要なエンドポイントに接続するには、`CredentialsProvider` を使用して認証情報を設定します。

import org.apache.hc.client5.http.auth.AuthScope;
import org.apache.hc.client5.http.auth.UsernamePasswordCredentials;
import org.apache.hc.client5.http.impl.auth.BasicCredentialsProvider;
import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
import org.apache.hc.client5.http.impl.classic.HttpClients;
public class BasicAuthExample { public static void main(String[] args) { // CredentialsProviderを作成し、認証情報を設定 BasicCredentialsProvider credentialsProvider = new BasicCredentialsProvider(); credentialsProvider.setCredentials( new AuthScope("httpbin.org", 443), // ターゲットホストとポート new UsernamePasswordCredentials("user", "passwd".toCharArray()) ); // CredentialsProviderを設定してHttpClientを構築 try (CloseableHttpClient httpClient = HttpClients.custom() .setDefaultCredentialsProvider(credentialsProvider) .build()) { // ... 認証が必要なURLへのリクエスト実行 ... } catch (Exception e) { e.printStackTrace(); } }
}

5.2. SSL/TLSのカスタマイズ

自己署名証明書を信頼したり、特定のTLSプロトコルバージョンを強制したりするなど、SSL/TLSの挙動をカスタマイズする必要がある場合があります。これには `SSLContext` と `SSLConnectionSocketFactory` を使用します。

注意: 以下の例ではすべての証明書を信頼するように設定していますが、これはセキュリティリスクを伴います。本番環境では、信頼する証明書をキーストアにインポートし、そのキーストアを読み込む方法を推奨します。

import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
import org.apache.hc.client5.http.impl.classic.HttpClients;
import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManagerBuilder;
import org.apache.hc.client5.http.io.HttpClientConnectionManager;
import org.apache.hc.client5.http.ssl.SSLConnectionSocketFactory;
import org.apache.hc.client5.http.ssl.TrustAllStrategy;
import org.apache.hc.core5.ssl.SSLContexts;
import javax.net.ssl.SSLContext;
public class CustomSslContext { public static void main(String[] args) throws Exception { // すべての証明書を信頼するSSLContextを作成 (テスト目的のみ) SSLContext sslContext = SSLContexts.custom() .loadTrustMaterial(null, new TrustAllStrategy()) .build(); // 作成したSSLContextでSSLConnectionSocketFactoryを初期化 SSLConnectionSocketFactory sslSocketFactory = new SSLConnectionSocketFactory(sslContext); // ConnectionManagerを構築する際にSSLConnectionSocketFactoryを指定 HttpClientConnectionManager connManager = PoolingHttpClientConnectionManagerBuilder.create() .setSSLSocketFactory(sslSocketFactory) .build(); // HttpClientを構築 try (CloseableHttpClient httpClient = HttpClients.custom() .setConnectionManager(connManager) .build()) { // このhttpClientは自己署名証明書などを持つHTTPSサイトに接続できる // ... リクエスト実行 ... } }
}

第6章: 非同期リクエスト (非同期クライアント)

HttpClient 5の大きな特徴の一つが、強力な非同期HTTPクライアントです。`CloseableHttpAsyncClient` を使用することで、I/O処理でスレッドをブロックすることなく、大量のリクエストを効率的に捌くことができます。これにより、スケーラビリティの高いアプリケーションを構築することが可能になります。

非同期クライアントは、使用を開始する前に `start()` メソッドを呼び出す必要がある点に注意してください。

6.1. `FutureCallback` を使った非同期処理

`FutureCallback` を使うことで、リクエストの完了時、失敗時、キャンセル時に実行される処理を定義できます。

import org.apache.hc.client5.http.async.methods.SimpleHttpRequest;
import org.apache.hc.client5.http.async.methods.SimpleHttpResponse;
import org.apache.hc.client5.http.async.methods.SimpleHttpRequests;
import org.apache.hc.client5.http.impl.async.CloseableHttpAsyncClient;
import org.apache.hc.client5.http.impl.async.HttpAsyncClients;
import org.apache.hc.core5.concurrent.FutureCallback;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Future;
public class AsyncRequestWithCallback { public static void main(String[] args) throws Exception { try (CloseableHttpAsyncClient asyncClient = HttpAsyncClients.createDefault()) { asyncClient.start(); SimpleHttpRequest request = SimpleHttpRequests.get("https://httpbin.org/get"); CountDownLatch latch = new CountDownLatch(1); System.out.println("Executing request..."); final Future<SimpleHttpResponse> future = asyncClient.execute(request, new FutureCallback<SimpleHttpResponse>() { @Override public void completed(SimpleHttpResponse response) { System.out.println(request.getRequestUri() + " -> " + response.getCode()); System.out.println(response.getBodyText()); latch.countDown(); } @Override public void failed(Exception ex) { System.out.println(request.getRequestUri() + " -> " + ex); latch.countDown(); } @Override public void cancelled() { System.out.println(request.getRequestUri() + " -> cancelled"); latch.countDown(); } }); // 非同期処理の完了を待つ latch.await(); System.out.println("Done."); } }
}

6.2. `CompletableFuture` との連携

Java 8以降で導入された `CompletableFuture` と連携させることで、よりモダンで柔軟な非同期処理のパイプラインを構築できます。`execute` メソッドの戻り値である `Future` を `CompletableFuture` に変換して利用します。

import org.apache.hc.client5.http.async.methods.SimpleHttpRequest;
import org.apache.hc.client5.http.async.methods.SimpleHttpResponse;
import org.apache.hc.client5.http.async.methods.SimpleHttpRequests;
import org.apache.hc.client5.http.impl.async.CloseableHttpAsyncClient;
import org.apache.hc.client5.http.impl.async.HttpAsyncClients;
import java.util.concurrent.CompletableFuture;
public class AsyncRequestWithCompletableFuture { public static void main(String[] args) throws Exception { try (CloseableHttpAsyncClient asyncClient = HttpAsyncClients.createDefault()) { asyncClient.start(); SimpleHttpRequest request1 = SimpleHttpRequests.get("https://httpbin.org/get?req=1"); SimpleHttpRequest request2 = SimpleHttpRequests.get("https://httpbin.org/get?req=2"); CompletableFuture<SimpleHttpResponse> future1 = toCompletableFuture(asyncClient.execute(request1, null)); CompletableFuture<SimpleHttpResponse> future2 = toCompletableFuture(asyncClient.execute(request2, null)); // 2つの非同期リクエストが両方完了したら処理を実行 CompletableFuture.allOf(future1, future2).join(); SimpleHttpResponse response1 = future1.get(); SimpleHttpResponse response2 = future2.get(); System.out.println("Response 1 status: " + response1.getCode()); System.out.println("Response 2 status: " + response2.getCode()); } } // FutureをCompletableFutureに変換するヘルパーメソッド public static <T> CompletableFuture<T> toCompletableFuture(java.util.concurrent.Future<T> future) { return CompletableFuture.supplyAsync(() -> { try { return future.get(); } catch (Exception e) { throw new RuntimeException(e); } }); }
}

第7章: エラーハンドリングとリトライ

ネットワーク通信にはエラーがつきものです。HttpClientには、リクエストの失敗をハンドリングし、自動的にリトライする仕組みが備わっています。

7.1. 代表的な例外

HttpClientを使用する際に遭遇する可能性のある代表的な例外は以下の通りです。

  • `java.net.SocketTimeoutException`: ソケットタイムアウト(レスポンスタイムアウト)が発生した場合にスローされます。
  • `org.apache.hc.core5.http.ConnectionRequestTimeoutException`: コネクションプールからの接続取得がタイムアウトした場合にスローされます。
  • `java.net.ConnectException`: ターゲットホストへの接続自体に失敗した場合(例: サーバーがダウンしている、ポートが閉じている)にスローされます。
  • `java.net.UnknownHostException`: ホスト名が解決できなかった場合にスローされます。
  • `javax.net.ssl.SSLException`: SSL/TLSハンドシェイク中に問題が発生した場合にスローされます。

7.2. リトライハンドラ (`HttpRequestRetryStrategy`)

HttpClientでは、リクエスト失敗時にリトライするかどうかを決定するロジックを `HttpRequestRetryStrategy` インターフェースを実装することでカスタマイズできます。例えば、サーバーが一時的な高負荷状態を示す503 (Service Unavailable) を返した場合にのみリトライする、といった戦略を実装できます。

デフォルトでは、べき等なリクエスト(GET, HEAD, PUT, DELETEなど)が特定のトランスポート例外で失敗した場合にリトライが試みられます。

import org.apache.hc.client5.http.HttpRequestRetryStrategy;
import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
import org.apache.hc.client5.http.impl.classic.HttpClientBuilder;
import org.apache.hc.core5.http.HttpResponse;
import org.apache.hc.core5.http.protocol.HttpContext;
import org.apache.hc.core5.util.TimeValue;
import java.io.IOException;
public class CustomRetryStrategy { public static void main(String[] args) { // カスタムリトライ戦略を定義 HttpRequestRetryStrategy myRetryStrategy = new HttpRequestRetryStrategy() { private final int maxRetries = 3; // 最大リトライ回数 private final TimeValue retryInterval = TimeValue.ofSeconds(2); // リトライ間隔 @Override public boolean retryRequest(HttpResponse response, int execCount, HttpContext context) { // 最大リトライ回数を超えていたらリトライしない if (execCount > maxRetries) { return false; } // 503 Service Unavailableの場合のみリトライ if (response.getCode() == 503) { System.out.println("Status 503. Retrying request... (" + execCount + "/" + maxRetries + ")"); return true; } return false; } @Override public boolean retryRequest(HttpRequest request, IOException exception, int execCount, HttpContext context) { // ここではIO例外に対するリトライロジックを定義できる // デフォルトの挙動に任せる場合はfalseを返す return false; } @Override public TimeValue getRetryInterval(HttpResponse response, int execCount, HttpContext context) { return retryInterval; } }; try (CloseableHttpClient httpClient = HttpClientBuilder.create() .setRetryStrategy(myRetryStrategy) .build()) { // ... リクエスト実行 ... } catch (Exception e) { e.printStackTrace(); } }
}

べき等性(Idempotence)への注意

POSTリクエストのようなべき等でない操作をリトライすると、意図しない副作用(例:同じデータが複数回作成される)を引き起こす可能性があります。リトライ戦略を実装する際は、対象とするHTTPメソッドとエラーの種類を慎重に検討する必要があります。

まとめ

この記事では、Apache HttpClient 5.xの基本的な使い方から、タイムアウト設定、コネクションプーリング、非同期リクエスト、エラーハンドリングといった応用的なトピックまでを幅広く解説しました。

HttpClientは非常に多機能で、ここで紹介した以外にも多くの機能が存在します。しかし、本記事で解説した内容をマスターすれば、ほとんどのWebサービスやAPIとの連携を堅牢かつ効率的に実装できるはずです。

重要なのは、`try-with-resources`による確実なリソース管理`PoolingHttpClientConnectionManager`によるパフォーマンスの最適化、そして`RequestConfig`による適切なタイムアウト設定です。これらの基本を抑え、ぜひ実際のプロジェクトでHttpClientを最大限に活用してください。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です