2.2. JAX-RS Client

2.2.1. JAX-RS Client API

JAX-RS 2.0 では、HTTP リクエストをリモート RESTful Web サービスに送信する新しいクライアント API が導入されました。3 つの主要クラスを持つ fluent request-building API です。

  • Client
  • WebTarget
  • Response

Client インターフェイスは WebTarget インスタンスのビルダーです。WebTarget は、サブリソース WebTargets をビルドしたり、リクエストを呼び出すための固有の URL または URL テンプレートを表します。

クライアントを作成する方法は、標準の方法か、ResteasyClientBuilder クラスを使用する方法です。ResteasyClientBuilder クラスを使用する利点は、クライアントを設定するヘルパーメソッドが他にもいくつか提供されることです。

ResteasyClientBuilder クラス はこれらのヘルパーメソッドを提供しますが、クラスは JBoss EAP API に固有のものです。アプリケーションを新しいサーバーに移行する場合は、アプリケーションを再構築する必要があります。ResteasyClientBuilder クラスは RESTEasy に依存し、クラスは移植できません。

JAX-RS および Java EE API 仕様の両方に準拠するクライアントを作成する標準的な方法は、JAX-RS 実装間で移植可能です。

注記

JAX-RS アプリケーションが移植可能な状態に保つには、Java EE API 仕様に従い、可能な場合は Java EE API アプリケーションを使用します。ユースケースが Java EE API の使用をサポートしない場合は、JBoss に固有の API のみを使用してください。

これらのガイドラインに従うと、アプリケーションを別のサーバーに移行する場合や、新しい Java EE と互換性のある JBoss 実装に移行する際に発生する可能性のある問題の数を減らすことができます。

標準の方法を使用したクライアントの作成

以下の例は、クライアントを作成するための標準的な方法のいずれかを示しています。

Client client = ClientBuilder.newClient();

また、別の標準的な方法を使用して、以下の例のようにクライアントを作成することもできます。

Client client = ClientBuilder.newBuilder().build();
WebTarget target = client.target("http://foo.com/resource");
Response response = target.request().get();
String value = response.readEntity(String.class);
response.close();  // You should close connections!
ResteasyClientBuilder クラスを使用したクライアントの作成

以下の例は、ResteasyClientBuilder クラスを使用してクライアントを作成します。

ResteasyClient client = new ResteasyClientBuilder().build();
ResteasyWebTarget target = client.target("http://foo.com/resource");

JAX-RS 2.1 では、2 つのタイムアウトメソッドを ClientBuilder クラスに追加できます。タイムアウトメソッドは仕様に準拠したメソッドであり、RESTEasy メソッドを使用する代わりに使用することができます。

以下の ClientBuilder 仕様に準拠したメソッドは、非推奨となった RESTEasy メソッドを置き換えます。

  • connectTimeout メソッドは establishConnectionTimeout メソッドに置き換わります。

    connectTimeout メソッドは、新しいサーバー接続を行うときにクライアントが待機する時間を決定します。

  • readTimeout メソッドは socketTimeout メソッドに置き換わります。

    readTimeout メソッドは、クライアントがサーバーからの応答を待つ時間を決定します。

以下の例は、connectTimeout メソッドおよび readTimeout メソッドの指定された値を示しています。

import javx.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.Client;

Client client = ClientBuilder.newBuilder()
	       .connectTimeout(100, TimeUnit.SECONDS)
	       .readTimeout(2, TimeUnit.SECONDS)
	       .build();

readTimeout は、既存の接続で実行されたリクエストに適用されることに注意してください。

注記

timeout パラメーターの値をゼロに設定すると、サーバーは永久に待機します。

RESTEasy は、META-INF/services/javax.ws.rs.ext.Providers ファイルにリストされているすべてのクラスを含むデフォルトのプロバイダーのセットを自動的に読み込みます。また、Client.configuration() メソッド呼び出しによって提供される設定オブジェクトを使用して、他のプロバイダー、フィルター、インターセプターを手動で登録できます。設定では、必要になる可能性のある設定プロパティーを設定することもできます。

WebTarget には、親インスタンスに登録されているコンポーネントおよびプロパティーを継承する設定インスタンスがあります。これにより、ユーザー名やパスワードなど、各ターゲットリソースに特定の設定オプションを設定できます。

その他のリソース

RESTEasy クライアントクラスの使用

RESTEasy クライアントの以下の依存関係を Maven pom.xml ファイルに追加する必要があります。

<dependency>
	<groupId>org.jboss.resteasy</groupId>
	<artifactId>resteasy-client</artifactId>
	<version>VERSION_IN_EAP</version>
 </dependency>

RESTEasy クライアントクラスを使用する作業例は、JBoss EAP に同梱される jaxrs-client および resteasy-jaxrs-client クイックスタートを参照してください。

クライアント側のフィルター

クライアント側のフィルターには、以下のタイプがあります。

ClientRequestFilter
ClientRequestFilter は、HTTP リクエストがサーバーへネットワーク経由で送信される前に実行されます。ClientRequestFilter は、要求の実行を中止し、サーバーへの接続を行わずに、実行可能な応答を提供することもできます。
ClientResponseFilter
ClientResponseFilter は、サーバーから応答を受信した後、応答本体がマーシャリング解除される前に実行されます。ClientResponseFilter は、応答オブジェクトをアプリケーションコードに移動する前に変更できます。以下の例は、これらの概念を示しています。
// execute request filters
for (ClientRequestFilter filter : requestFilters) {
	filter.filter(requestContext);
	if (isAborted(requestContext)) {
    return requestContext.getAbortedResponseObject();
  }
}

// send request over the wire
response = sendRequest(request);

// execute response filters
for (ClientResponseFilter filter : responseFilters) {
	filter.filter(requestContext, responseContext);
}
クライアントリクエストへのクライアント側のフィルターの登録

以下の例は、クライアント側のフィルターをクライアント要求に登録する方法を表しています。

client = ClientBuilder.newClient();
WebTarget base = client.target(generateURL("/") + "get");
base.register(ClientExceptionsCustomClientResponseFilter.class).request("text/plain").get();
クライアント側のキャッシュ

RESTEasy には、クライアント側のキャッシュを設定する機能があります。このキャッシュは、サーバーの応答と共に送信されるキャッシュ制御ヘッダーを検索します。cache-control ヘッダーがクライアントが応答のキャッシュを許可するように指定すると、RESTEasy はローカルメモリー内にこれをキャッシュします。

ResteasyWebTarget target = client.target(generateBaseUrl());
target.register(BrowserCacheFeature.class);
チャンク化されたエンコーディングサポート

RESTEasy は、リクエストを チャンク 転送モードで送信するよう指定する機能をクライアント API に提供します。以下のように、チャンク された転送モードを指定する方法を使用できます。

  • org.jboss.resteasy.client.jaxrs.ResteasyWebTarget を設定して、すべてのリクエストをチャンクモードで送信することができます。

    ResteasyClient client = new ResteasyClientBuilder().build();
    ResteasyWebTarget target = client.target("http://localhost:8081/test");
    target.setChunked(b.booleanValue());
    Invocation.Builder request = target.request();
  • または、特定のリクエストをチャンクモードで送信するように設定することもできます。

    ResteasyClient client = new ResteasyClientBuilder().build();
    ResteasyWebTarget target = client.target("http://localhost:8081/test");
    ClientInvocationBuilder request = (ClientInvocationBuilder) target.request();
    request.setChunked(b);

    javax.ws.rs.client.Invocation.Builder クラスとは異なり org.jboss.resteasy.client.jaxrs.internal.ClientInvocationBuilder は RESTEasy クラスです。

注記

チャンクモードでリクエストを送信する機能は、基盤のトランスポート層によって異なります。特に、使用されている org.jboss.resteasy.client.jaxrs.ClientHttpEngine クラスの実装によって異なります。現時点では、デフォルトの実装 ApacheHttpClient43Engine と以前の実装の ApacheHttpClient4Engine のみが、チャンクモードをサポートします。これらはいずれも org.jboss.resteasy.client.jaxrs.engines パッケージで利用できます。詳細は、Implementing RESTEasy with HTTP Client を参照してください。

2.2.2. HTTP クライアントによる RESTEasy の実装

クライアントとサーバー間のネットワーク通信は、RESTEasy でデフォルトで処理されます。Apache HttpComponents プロジェクトの HttpClient HttpClient を使用します。RESTEasy クライアントフレームワークとネットワークの間のインターフェイスは、ClientHttpEngine インターフェイスによって定義されます。

RESTEasy には、このインターフェイスの 4 つの実装が同梱されています。デフォルトの実装は ApacheHttpClient43Engine です。この実装は Apache 4.3 を使用します。

ApacheHttpClient4Engine は、Apache 4.3 よりも前のバージョンを使用する実装です。このクラスは後方互換性を提供します。RESTEasy は、Apache バージョンの検出に基づいて、これらの 2 つの ClientHttpEngine 実装のいずれかを自動的に選択します。InMemoryClientEngine は、同じ JVM のサーバーにリクエストをディスパッチする実装で、URLConnectionEnginejava.net.HttpURLConnection を使用する実装です。

クライアントエグゼキューターは、特定の ClientRequest に渡すことができます。

ResteasyClient client = new
ResteasyClientBuilder().httpEngine(engine).build();

RESTEasy および HttpClient は、HttpClient を参照せずに、デフォルトのクライアントフレームワークを使用するように決定します。ただし、一部のアプリケーションでは、HttpClient の詳細を閲覧する必要がある場合があります。ApacheHttpClient43Engine および ApacheHttpClient4Engine は、org.apache.http.client.HttpClientorg.apache.http.protocol.HttpContext のインスタンスで提供できます。これは、HttpClient レイヤーに追加の設定詳細を実行できます。たとえば、認証は以下のように設定できます。

// Configure HttpClient to authenticate preemptively
// by prepopulating the authentication data cache.

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

// 2. Generate BASIC scheme object and add it to the local auth cache
AuthScheme basicAuth = new BasicScheme();
authCache.put(new HttpHost("sippycups.bluemonkeydiamond.com"), basicAuth);

// 3. Add AuthCache to the execution context
BasicHttpContext localContext = new BasicHttpContext();
localContext.setAttribute(ClientContext.AUTH_CACHE, authCache);

// 4. Create client executor and proxy
HttpClient httpClient = HttpClientBuilder.create().build();
ApacheHttpClient4Engine engine = new ApacheHttpClient4Engine(httpClient, localContext);
ResteasyClient client = new ResteasyClientBuilder().httpEngine(engine).build();

HttpContextProvider は RESTEasy が提供するインターフェイスで、これを使用してカスタム HttpContextApacheHttpClient43Engine および ApacheHttpClient4Engine 実装に提供できます。

注記

コネクションの解放とコネクションのクローズの違いを理解しておくことが重要となります。接続を解放すると、接続が再利用できるようになります。接続を閉じると、そのリソースが解放され、使用できなくなります。

RESTEasy は通知なしで接続をリリースします。唯一のカウンター例は、応答が InputStream のインスタンスであるケースです。これは明示的に閉じる必要があります。

一方、呼び出しの結果が Response のインスタンスである場合は、Response.close() メソッドを使用して接続を解放する必要があります。

WebTarget target = client.target("http://localhost:8081/customer/123");
Response response = target.request().get();
System.out.println(response.getStatus());
response.close();

これは try-finally ブロックで実行できます。接続を解放すると、接続を別のことに利用できるようになります。通常、ソケットを閉じることはありません。

ApacheHttpClient4Engine.finalize() は、使用中の HttpClient を作成した場合に、開いているソケットを閉じます。finalize() を呼び出すために JDK を使用するのは安全ではありません。HttpClientApacheHttpClient4Executor に渡される場合、ユーザーは以下のように接続を閉じる必要があります。

HttpClient httpClient = new HttpClientBuilder.create().build();
ApacheHttpClient4Engine executor = new ApacheHttpClient4Engine(httpClient);
...
httpClient.getConnectionManager().shutdown();
注記

ApacheHttpClient4EngineHttpClient の独自のインスタンスを作成した場合は finalize() がオープンソケットを閉じるのを待つ必要はありません。ClientHttpEngine インターフェイスには、この目的のために close() メソッドがあります。

最後に、javax.ws.rs.client.Client クラスがエンジンを自動的に作成している場合は、Client.close() を呼び出します。この呼び出しにより、ソケット接続がクリーンアップされます。

2.2.2.1. HTTP リダイレクト

Apache HttpClient をベースとする ClientHttpEngine 実装 は HTTP リダイレクトをサポートします。この機能はデフォルトで無効になっています。これを有効にするには、以下のように setFollowRedirects メソッドを true に設定します。

ApacheHttpClient43Engine engine = new ApacheHttpClient43Engine();
engine.setFollowRedirects(true);
Client client = new ResteasyClientBuilder().httpEngine(engine).build();