高度なHttpClient設定

高度なHttpClient設定

1. 概要

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

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

HTTPサーバーのスタブ化にWiremockを使用します。 Wiremockについて詳しく知りたい場合は、this articleを確認してください。

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

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

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

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

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

String userAgent = "exampleAgent/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()メソッドを介して送信します。

「exampleAgent / 1.0」に等しい値を持つヘッダーUser-Agentを持つURL/detailに対してGET要求が送信されると、serviceMockは200のHTTP応答コードを返します。

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

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

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

String xmlBody = "1";
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サービスはbehind a proxy serverであり、追加のロジックを実行したり、静的リソースをキャッシュしたりします。 HTTPクライアントを作成して実際のサービスにリクエストを送信する場合、すべてのHTTPリクエストでそれを処理する必要はありません。

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

@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クライアントを構成する

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

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

1人のユーザーのみを承認するプロキシサーバーがあるとします–“username_admin, with password“secret_password.

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

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呼び出しを実行するようにApacheHttpClientを構成する方法を示します。 プロキシサーバー経由でリクエストを送信する方法と、プロキシ経由で認証する方法を見ました。

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