最新の安定バージョンについては、Spring Framework 6.2.11 を使用してください! |
REST クライアント
Spring Framework は、REST エンドポイントを呼び出すために次の選択肢を提供します。
WebClient
- 流れるような API を備えたノンブロッキングでリアクティブなクライアント。RestTemplate
- テンプレートメソッド API を使用した同期クライアント。HTTP インターフェース - 生成された動的プロキシ実装を備えたアノテーション付きインターフェース。
WebClient
WebClient
は、HTTP リクエストを実行するためのノンブロッキングのリアクティブクライアントです。これは 5.0 で導入され、同期、非同期、ストリーミングのシナリオをサポートする RestTemplate
の代替手段を提供します。
WebClient
は以下をサポートします。
ノンブロッキング I/O。
Reactive Streams のバックプレッシャー。
より少ないハードウェアリソースで高い同時実行性。
Java 8 ラムダを活用する関数スタイルの流れるような API。
同期および非同期の相互作用。
サーバーへのストリーミングまたはサーバーからのストリーミング。
詳細については、WebClient を参照してください。
RestTemplate
RestTemplate
は、HTTP クライアントライブラリを介した高レベルの API を提供します。REST エンドポイントを 1 行で簡単に呼び出すことができます。オーバーロードされたメソッドの次のグループを公開します。
RestTemplate はメンテナンスモードであり、マイナーな変更とバグのリクエストのみが受け入れられます。代わりに WebClient の使用を検討してください。 |
メソッドグループ | 説明 |
---|---|
| GET を介して表現を取得します。 |
| GET を使用して |
| HEAD を使用して、リソースのすべてのヘッダーを取得します。 |
| POST を使用して新しいリソースを作成し、レスポンスから |
| POST を使用して新しいリソースを作成し、レスポンスから表現を返します。 |
| POST を使用して新しいリソースを作成し、レスポンスから表現を返します。 |
| PUT を使用してリソースを作成または更新します。 |
| PATCH を使用してリソースを更新し、レスポンスから表現を返します。JDK |
| DELETE を使用して、指定された URI のリソースを削除します。 |
| ALLOW を使用して、リソースに許可された HTTP メソッドを取得します。 |
| 必要に応じて柔軟性を高める、前述のメソッドのより一般化された(そしてあまり独自ではない)バージョン。 これらのメソッドでは、 |
| コールバックインターフェースを介したリクエストの準備とレスポンスの抽出を完全に制御して、リクエストを実行する最も一般的な方法。 |
初期化
デフォルトのコンストラクターは、リクエストを実行するために java.net.HttpURLConnection
を使用します。ClientHttpRequestFactory
の実装を使用して、別の HTTP ライブラリに切り替えることができます。現在、Apache HttpComponents と OkHttp の組み込みサポートもあります。
例: Apache HttpComponents に切り替えるには、次のようにします。
RestTemplate template = new RestTemplate(new HttpComponentsClientHttpRequestFactory());
各 ClientHttpRequestFactory
は、基礎となる HTTP クライアントライブラリに固有の構成オプションを公開します。たとえば、資格情報、接続プーリング、その他の詳細などです。
HTTP リクエストの java.net 実装は、エラー(401 など)を表すレスポンスのステータスにアクセスするときに例外を発生させる可能性があることに注意してください。これが課題になる場合は、別の HTTP クライアントライブラリに切り替えてください。 |
RestTemplate は、メトリクスとトレースを生成するために、可観測性のためにインストルメント化できます。RestTemplate 可観測性のサポートセクションを参照してください。 |
URI
RestTemplate
メソッドの多くは、String
変数引数として、または Map<String,String>
として URI テンプレートおよび URI テンプレート変数を受け入れます。
次の例では、String
変数引数を使用しています。
String result = restTemplate.getForObject(
"https://example.com/hotels/{hotel}/bookings/{booking}", String.class, "42", "21");
次の例では、Map<String, String>
を使用しています。
Map<String, String> vars = Collections.singletonMap("hotel", "42");
String result = restTemplate.getForObject(
"https://example.com/hotels/{hotel}/rooms/{hotel}", String.class, vars);
次の例に示すように、URI テンプレートは自動的にエンコードされることに注意してください。
restTemplate.getForObject("https://example.com/hotel list", String.class);
// Results in request to "https://example.com/hotel%20list"
RestTemplate
の uriTemplateHandler
プロパティを使用して、URI のエンコード方法をカスタマイズできます。または、java.net.URI
を準備して、URI
を受け入れる RestTemplate
メソッドの 1 つに渡すことができます。
URI の操作とエンコードの詳細については、URI リンクを参照してください。
ヘッダー
次の例に示すように、exchange()
メソッドを使用してリクエストヘッダーを指定できます。
String uriTemplate = "https://example.com/hotels/{hotel}";
URI uri = UriComponentsBuilder.fromUriString(uriTemplate).build(42);
RequestEntity<Void> requestEntity = RequestEntity.get(uri)
.header("MyRequestHeader", "MyValue")
.build();
ResponseEntity<String> response = template.exchange(requestEntity, String.class);
String responseHeader = response.getHeaders().getFirst("MyResponseHeader");
String body = response.getBody();
ResponseEntity
を返す多くの RestTemplate
メソッドバリアントを介してレスポンスヘッダーを取得できます。
本文
RestTemplate
メソッドに渡されたオブジェクトと RestTemplate
メソッドから返されたオブジェクトは、HttpMessageConverter
を使用して生のコンテンツとの間で変換されます。
POST では、次の例に示すように、入力オブジェクトはリクエスト本文に直列化されます。
URI location = template.postForLocation("https://example.com/people", person);
リクエストの Content-Type ヘッダーを明示的に設定する必要はありません。ほとんどの場合、ソース Object
型に基づいて互換性のあるメッセージコンバーターを見つけることができ、選択したメッセージコンバーターはそれに応じてコンテンツ型を設定します。必要に応じて、exchange
メソッドを使用して明示的に Content-Type
リクエストヘッダーを提供できます。これにより、選択されるメッセージコンバーターに影響を与えます。
GET では、次の例に示すように、レスポンスの本文が出力 Object
に逆直列化されます。
Person person = restTemplate.getForObject("https://example.com/people/{id}", Person.class, 42);
リクエストの Accept
ヘッダーを明示的に設定する必要はありません。ほとんどの場合、予期されるレスポンス型に基づいて互換性のあるメッセージコンバーターを見つけることができます。これにより、Accept
ヘッダーにデータが入力されます。必要に応じて、exchange
メソッドを使用して、Accept
ヘッダーを明示的に提供できます。
デフォルトでは、RestTemplate
は、オプションの変換ライブラリが存在するかどうかを判断するのに役立つクラスパスチェックに応じて、すべての組み込みメッセージコンバーターを登録します。明示的に使用するようにメッセージコンバーターを設定することもできます。
メッセージ変換
spring-web
モジュールには、InputStream
および OutputStream
を介して HTTP リクエストとレスポンスの本文を読み書きするための HttpMessageConverter
契約が含まれています。HttpMessageConverter
インスタンスは、クライアント側 (たとえば、RestTemplate
) とサーバー側 (たとえば、Spring MVC REST コントローラー) で使用されます。
メインメディア(MIME)型の具体的な実装はフレームワークで提供され、デフォルトでクライアント側では RestTemplate
に、サーバー側では RequestMappingHandlerAdapter
に登録されます(メッセージコンバーターの構成を参照)。
HttpMessageConverter
の実装については、次のセクションで説明します。すべてのコンバーターで、デフォルトのメディア型が使用されますが、supportedMediaTypes
Bean プロパティを設定することでそれをオーバーライドできます。次の表は、各実装について説明しています。
MessageConverter | 説明 |
---|---|
| HTTP リクエストおよびレスポンスから |
| HTTP リクエストとレスポンスからフォームデータを読み書きできる |
| HTTP リクエストとレスポンスからバイト配列を読み書きできる |
|
|
| Jackson の |
| Jackson XML [GitHub] (英語) 拡張機能の |
| HTTP リクエストおよびレスポンスから |
| HTTP リクエストおよびレスポンスから |
Jackson JSON ビュー
次の例に示すように、Jackson JSON ビュー (英語) を指定して、オブジェクトプロパティのサブセットのみを直列化できます。
MappingJacksonValue value = new MappingJacksonValue(new User("eric", "7!jd#h23"));
value.setSerializationView(User.WithoutPasswordView.class);
RequestEntity<MappingJacksonValue> requestEntity =
RequestEntity.post(new URI("https://example.com/user")).body(value);
ResponseEntity<String> response = template.exchange(requestEntity, String.class);
マルチパート
マルチパートデータを送信するには、値がパーツコンテンツ用の Object
、ファイルパーツ用の Resource
、ヘッダー付きパーツコンテンツ用の HttpEntity
である MultiValueMap<String, Object>
を提供する必要があります。例:
MultiValueMap<String, Object> parts = new LinkedMultiValueMap<>();
parts.add("fieldPart", "fieldValue");
parts.add("filePart", new FileSystemResource("...logo.png"));
parts.add("jsonPart", new Person("Jason"));
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_XML);
parts.add("xmlPart", new HttpEntity<>(myBean, headers));
ほとんどの場合、各パーツに Content-Type
を指定する必要はありません。コンテンツ型は、直列化するために選択された HttpMessageConverter
に基づいて自動的に決定されます。Resource
の場合は、ファイル拡張子に基づいて決定されます。必要に応じて、MediaType
に HttpEntity
ラッパーを明示的に提供できます。
MultiValueMap
の準備ができたら、以下に示すように RestTemplate
に渡すことができます。
MultiValueMap<String, Object> parts = ...;
template.postForObject("https://example.com/upload", parts, Void.class);
MultiValueMap
に少なくとも 1 つの非 String
値が含まれている場合、Content-Type
は FormHttpMessageConverter
によって multipart/form-data
に設定されます。MultiValueMap
に String
値がある場合、Content-Type
は application/x-www-form-urlencoded
にデフォルト設定されます。必要に応じて、Content-Type
を明示的に設定することもできます。
HTTP インターフェース
Spring Framework を使用すると、HTTP サービスを HTTP 交換用のアノテーション付きメソッドを備えた Java インターフェースとして定義できます。次に、このインターフェースを実装して交換を実行するプロキシを生成できます。これは、HTTP リモートアクセスを簡素化できます。これには、基盤となる HTTP クライアントの使用の詳細をラップするファサードが含まれることがよくあります。
1 つは、@HttpExchange
メソッドを使用してインターフェースを宣言することです。
interface RepositoryService {
@GetExchange("/repos/{owner}/{repo}")
Repository getRepository(@PathVariable String owner, @PathVariable String repo);
// more HTTP exchange methods...
}
2 つ目は、宣言された HTTP 交換を実行するプロキシを作成することです。
WebClient client = WebClient.builder().baseUrl("https://api.github.com/").build();
HttpServiceProxyFactory factory = HttpServiceProxyFactory.builder(WebClientAdapter.forClient(client)).build();
RepositoryService service = factory.createClient(RepositoryService.class);
@HttpExchange
は、すべてのメソッドに適用される型レベルでサポートされています。
@HttpExchange(url = "/repos/{owner}/{repo}", accept = "application/vnd.github.v3+json")
interface RepositoryService {
@GetExchange
Repository getRepository(@PathVariable String owner, @PathVariable String repo);
@PatchExchange(contentType = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
void updateRepository(@PathVariable String owner, @PathVariable String repo,
@RequestParam String name, @RequestParam String description, @RequestParam String homepage);
}
メソッドパラメーター
アノテーション付きの HTTP 交換メソッドは、次のメソッドパラメーターを使用して柔軟なメソッドシグネチャーをサポートします。
メソッド引数 | 説明 |
---|---|
| アノテーションの |
| アノテーションの |
| リクエストヘッダーまたは複数のヘッダーを追加します。引数は、複数のヘッダーを持つ |
| リクエスト URL にプレースホルダーを展開するための変数を追加します。引数は、複数の変数を持つ |
| リクエストの本文を、直列化するオブジェクトとして、または Reactive Streams |
| リクエストパラメーターまたは複数のパラメーターを追加します。引数は、複数のパラメーターを持つ
|
| リクエストパートを追加します。リクエストパートは、String (フォームフィールド)、 |
| 1 つまたは複数の Cookie を追加します。引数は、複数の Cookie を持つ |
戻り値
アノテーション付きの HTTP 交換メソッドは、次の戻り値をサポートします。
メソッドの戻り値 | 説明 |
---|---|
| 指定されたリクエストを実行し、レスポンスコンテンツがある場合はそれを解放します。 |
| 指定されたリクエストを実行し、レスポンスコンテンツがある場合はそれを解放して、レスポンスヘッダーを返します。 |
| 指定されたリクエストを実行し、レスポンスの内容を宣言された戻り値の型にデコードします。 |
| 指定されたリクエストを実行し、レスポンスコンテンツを宣言された要素型のストリームにデコードします。 |
| 指定されたリクエストを実行し、レスポンスコンテンツがある場合はそれを解放して、ステータスとヘッダーを含む |
| 指定されたリクエストを実行し、レスポンスコンテンツを宣言された戻り値の型にデコードし、ステータス、ヘッダー、デコードされた本文を含む |
| 指定されたリクエストを実行し、レスポンスコンテンツを宣言された要素型のストリームにデコードし、ステータス、ヘッダー、デコードされたレスポンス本文ストリームを含む |
ReactiveAdapterRegistry に登録されている他の非同期型またはリアクティブ型を使用することもできます。 |
例外処理
デフォルトでは、WebClient
は 4xx および 5xx HTTP ステータスコードに対して WebClientResponseException
を発生させます。これをカスタマイズするには、クライアントを介して実行されるすべてのレスポンスに適用されるレスポンスステータスハンドラーを登録します。
WebClient webClient = WebClient.builder()
.defaultStatusHandler(HttpStatusCode::isError, resp -> ...)
.build();
WebClientAdapter clientAdapter = WebClientAdapter.forClient(webClient);
HttpServiceProxyFactory factory = HttpServiceProxyFactory
.builder(clientAdapter).build();
エラーステータスコードの抑制などの詳細とオプションについては、WebClient.Builder
の defaultStatusHandler
の Javadoc を参照してください。