1. 概要

この記事では、Apache HttpClientライブラリの高度な使用法について説明します。

HTTPリクエストにカスタムヘッダーを追加する例を見て、プロキシサーバーを介してリクエストを承認して送信するようにクライアントを構成する方法を見ていきます。

HTTPサーバーのスタブにはWiremockを使用します。 Wiremockの詳細については、この記事をご覧ください。

2. カスタムUser-Agentヘッダーを使用したHTTPリクエスト

カスタムUser-AgentヘッダーをHTTPGETリクエストに追加するとします。 User-Agent headerには、ネットワークプロトコルピアがアプリケーションタイプ、オペレーティングシステム、ソフトウェアベンダー、または要求元のソフトウェアユーザーエージェントのソフトウェアバージョンを識別できるようにする特性文字列が含まれています。

HTTPクライアントの作成を開始する前に、組み込みのモックサーバーを起動する必要があります。

@Rule
public WireMockRule serviceMock = new WireMockRule(8089);

HttpGet インスタンスを作成するときは、 setHeader()メソッドを使用して、ヘッダーの名前と値を渡すことができます。 そのヘッダーはHTTPリクエストに追加されます:

String userAgent = "BaeldungAgent/1.0"; 
HttpClient httpClient = HttpClients.createDefault();

HttpGet httpGet = new HttpGet("http://localhost:8089/detail");
httpGet.setHeader(HttpHeaders.USER_AGENT, userAgent);

HttpResponse response = httpClient.execute(httpGet);

assertEquals(response.getStatusLine().getStatusCode(), 200);

User-Agent ヘッダーを追加し、 execute()メソッドを介してそのリクエストを送信します。

「BaeldungAgent/1.0」に等しい値を持つヘッダーUser-Agentを含むURL/ detail に対してGETリクエストが送信されると、serviceMockは200HTTPを返します。応答コード:

serviceMock.stubFor(get(urlEqualTo("/detail"))
  .withHeader("User-Agent", equalTo(userAgent))
  .willReturn(aResponse().withStatus(200)));

3. POSTリクエスト本文でのデータの送信

通常、HTTP POSTメソッドを実行するときは、エンティティをリクエストの本文として渡します。 HttpPost オブジェクトのインスタンスを作成する場合、 setEntity()メソッドを使用してそのリクエストに本文を追加できます。

String xmlBody = "<xml><id>1</id></xml>";
HttpClient httpClient = HttpClients.createDefault();
HttpPost httpPost = new HttpPost("http://localhost:8089/person");
httpPost.setHeader("Content-Type", "application/xml");

StringEntity xmlEntity = new StringEntity(xmlBody);
httpPost.setEntity(xmlEntity);

HttpResponse response = httpClient.execute(httpPost);

assertEquals(response.getStatusLine().getStatusCode(), 200);

XML形式の本文を持つStringEntityインスタンスを作成しています。 Content-Typeヘッダーを「application/ xml 」に設定して、送信するコンテンツのタイプに関する情報をサーバーに渡すことが重要です。 serviceMock がXML本文を含むPOST要求を受信すると、ステータスコード200OKで応答します。

serviceMock.stubFor(post(urlEqualTo("/person"))
  .withHeader("Content-Type", equalTo("application/xml"))
  .withRequestBody(equalTo(xmlBody))
  .willReturn(aResponse().withStatus(200)));

4. プロキシサーバーを介したリクエストの送信

多くの場合、当社のWebサービスは、いくつかの追加ロジックを実行したり、静的リソースをキャッシュしたりするプロキシサーバーの背後にあることができます。 HTTPクライアントを作成して実際のサービスにリクエストを送信する場合、すべてのHTTPリクエストでそれを処理する必要はありません。

このシナリオをテストするには、別の組み込みWebサーバーを起動する必要があります。

@Rule
public WireMockRule proxyMock = new WireMockRule(8090);

2つの組み込みサーバーでは、最初の実際のサービスは8089ポート上にあり、プロキシサーバーは8090ポート上でリッスンしています。

HttpHostインスタンスプロキシを引数として取るDefaultProxyRoutePlannerを作成することにより、プロキシ経由ですべてのリクエストを送信するようにHttpClientを構成しています。

HttpHost proxy = new HttpHost("localhost", 8090);
DefaultProxyRoutePlanner routePlanner = new DefaultProxyRoutePlanner(proxy);
HttpClient httpclient = HttpClients.custom()
  .setRoutePlanner(routePlanner)
  .build();

プロキシサーバーは、すべてのリクエストを8090ポートでリッスンする実際のサービスにリダイレクトしています。 テストの最後に、リクエストがプロキシ経由で実際のサービスに送信されたことを確認します。

proxyMock.stubFor(get(urlMatching(".*"))
  .willReturn(aResponse().proxiedFrom("http://localhost:8089/")));

serviceMock.stubFor(get(urlEqualTo("/private"))
  .willReturn(aResponse().withStatus(200)));

assertEquals(response.getStatusLine().getStatusCode(), 200);
proxyMock.verify(getRequestedFor(urlEqualTo("/private")));
serviceMock.verify(getRequestedFor(urlEqualTo("/private")));

5. プロキシ経由で認証するようにHTTPクライアントを構成する

前の例を拡張すると、プロキシサーバーを使用して認証を実行する場合があります。 このような構成では、プロキシはすべての要求を承認し、プロキシの背後に隠されているサーバーにそれらを渡すことができます。

承認プロセスの実行に使用される承認ヘッダーとともに、プロキシ経由で各リクエストを送信するようにHttpClientを構成できます。

username_adminパスワード「secret_passwordの1人のユーザーのみを許可するプロキシサーバーがあるとします。

プロキシ経由で承認されるユーザーの資格情報を使用して、BasicCredentialsProviderインスタンスを作成する必要があります。 HttpClientに適切な値のAuthorization ヘッダーを自動的に追加するには、提供された資格情報とBasicAuthCacheを使用してHttpClientContextを作成する必要があります。クレデンシャルを保存します:

HttpHost proxy = new HttpHost("localhost", 8090);
DefaultProxyRoutePlanner routePlanner = new DefaultProxyRoutePlanner(proxy);

//Client credentials
CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
credentialsProvider.setCredentials(new AuthScope(proxy), 
  new UsernamePasswordCredentials("username_admin", "secret_password"));

// Create AuthCache instance
AuthCache authCache = new BasicAuthCache();

BasicScheme basicAuth = new BasicScheme();
authCache.put(proxy, basicAuth);
HttpClientContext context = HttpClientContext.create();
context.setCredentialsProvider(credentialsProvider);
context.setAuthCache(authCache);

HttpClient httpclient = HttpClients.custom()
  .setRoutePlanner(routePlanner)
  .setDefaultCredentialsProvider(credentialsProvider)
  .build();

HttpClientを設定すると、サービスにリクエストを送信すると、Authorizationヘッダーを使用してプロキシ経由でリクエストが送信されて承認プロセスが実行されます。 各リクエストで自動的に設定されます。

サービスへの実際のリクエストを実行してみましょう。

HttpGet httpGet = new HttpGet("http://localhost:8089/private");
HttpResponse response = httpclient.execute(httpGet, context);

httpClientexecute()メソッドを構成で検証すると、リクエストがAuthorizationヘッダーを持つプロキシを通過したことが確認されます。

proxyMock.stubFor(get(urlMatching("/private"))
  .willReturn(aResponse().proxiedFrom("http://localhost:8089/")));
serviceMock.stubFor(get(urlEqualTo("/private"))
  .willReturn(aResponse().withStatus(200)));

assertEquals(response.getStatusLine().getStatusCode(), 200);
proxyMock.verify(getRequestedFor(urlEqualTo("/private"))
  .withHeader("Authorization", containing("Basic")));
serviceMock.verify(getRequestedFor(urlEqualTo("/private")));

6. 結論

この記事では、高度なHTTP呼び出しを実行するようにApache HttpClientを構成する方法を示します。 プロキシサーバーを介してリクエストを送信する方法と、プロキシを介して承認する方法を見ました。

これらすべての例とコードスニペットの実装は、 GitHubプロジェクトにあります。これはMavenプロジェクトであるため、そのままインポートして実行するのは簡単です。