URI リンク
このセクションでは、URI を準備するために Spring Framework で使用可能なさまざまなオプションについて説明します。
UriComponents
UriComponentsBuilder は、次の例に示すように、変数を持つ URI テンプレートから URI を作成できます。
Java
Kotlin
UriComponents uriComponents = UriComponentsBuilder
.fromUriString("https://example.com/hotels/{hotel}") (1)
.queryParam("q", "{q}") (2)
.encode() (3)
.build(); (4)
URI uri = uriComponents.expand("Westin", "123").toUri(); (5)| 1 | URI テンプレートを使用した静的ファクトリメソッド。 |
| 2 | URI コンポーネントを追加または置換します。 |
| 3 | URI テンプレートと URI 変数をエンコードするようリクエストします。 |
| 4 | UriComponents をビルドします。 |
| 5 | 変数を展開し、URI を取得します。 |
val uriComponents = UriComponentsBuilder
.fromUriString("https://example.com/hotels/{hotel}") (1)
.queryParam("q", "{q}") (2)
.encode() (3)
.build() (4)
val uri = uriComponents.expand("Westin", "123").toUri() (5)| 1 | URI テンプレートを使用した静的ファクトリメソッド。 |
| 2 | URI コンポーネントを追加または置換します。 |
| 3 | URI テンプレートと URI 変数をエンコードするようリクエストします。 |
| 4 | UriComponents をビルドします。 |
| 5 | 変数を展開し、URI を取得します。 |
前述の例は、次の例に示すように、1 つのチェーンに統合し、buildAndExpand で短縮できます。
Java
Kotlin
URI uri = UriComponentsBuilder
.fromUriString("https://example.com/hotels/{hotel}")
.queryParam("q", "{q}")
.encode()
.buildAndExpand("Westin", "123")
.toUri();val uri = UriComponentsBuilder
.fromUriString("https://example.com/hotels/{hotel}")
.queryParam("q", "{q}")
.encode()
.buildAndExpand("Westin", "123")
.toUri()次の例に示すように、URI に直接移動することで(エンコードを暗示する)、さらに短くすることができます。
Java
Kotlin
URI uri = UriComponentsBuilder
.fromUriString("https://example.com/hotels/{hotel}")
.queryParam("q", "{q}")
.build("Westin", "123");val uri = UriComponentsBuilder
.fromUriString("https://example.com/hotels/{hotel}")
.queryParam("q", "{q}")
.build("Westin", "123")次の例に示すように、完全な URI テンプレートを使用してさらに短縮できます。
Java
Kotlin
URI uri = UriComponentsBuilder
.fromUriString("https://example.com/hotels/{hotel}?q={q}")
.build("Westin", "123");val uri = UriComponentsBuilder
.fromUriString("https://example.com/hotels/{hotel}?q={q}")
.build("Westin", "123")UriBuilder
Spring MVC および Spring WebFlux
UriComponentsBuilder は UriBuilder を実装しています。UriBuilderFactory を使用して、UriBuilder を作成できます。UriBuilderFactory と UriBuilder は、ベース URL、エンコード設定、その他の詳細などの共有構成に基づいて、URI テンプレートから URI を構築するプラグ可能なメカニズムを提供します。
RestTemplate および WebClient を UriBuilderFactory で構成して、URI の準備をカスタマイズできます。DefaultUriBuilderFactory は、UriComponentsBuilder を内部で使用し、共有構成オプションを公開する UriBuilderFactory のデフォルト実装です。
次の例は、RestTemplate を構成する方法を示しています。
Java
Kotlin
// import org.springframework.web.util.DefaultUriBuilderFactory.EncodingMode;
String baseUrl = "https://example.org";
DefaultUriBuilderFactory factory = new DefaultUriBuilderFactory(baseUrl);
factory.setEncodingMode(EncodingMode.TEMPLATE_AND_VALUES);
RestTemplate restTemplate = new RestTemplate();
restTemplate.setUriTemplateHandler(factory);// import org.springframework.web.util.DefaultUriBuilderFactory.EncodingMode
val baseUrl = "https://example.org"
val factory = DefaultUriBuilderFactory(baseUrl)
factory.encodingMode = EncodingMode.TEMPLATE_AND_VALUES
val restTemplate = RestTemplate()
restTemplate.uriTemplateHandler = factory 次の例では、WebClient を構成します。
Java
Kotlin
// import org.springframework.web.util.DefaultUriBuilderFactory.EncodingMode;
String baseUrl = "https://example.org";
DefaultUriBuilderFactory factory = new DefaultUriBuilderFactory(baseUrl);
factory.setEncodingMode(EncodingMode.TEMPLATE_AND_VALUES);
WebClient client = WebClient.builder().uriBuilderFactory(factory).build();// import org.springframework.web.util.DefaultUriBuilderFactory.EncodingMode
val baseUrl = "https://example.org"
val factory = DefaultUriBuilderFactory(baseUrl)
factory.encodingMode = EncodingMode.TEMPLATE_AND_VALUES
val client = WebClient.builder().uriBuilderFactory(factory).build() さらに、DefaultUriBuilderFactory を直接使用することもできます。UriComponentsBuilder の使用に似ていますが、次の例に示すように、静的ファクトリメソッドの代わりに、構成と設定を保持する実際のインスタンスです。
Java
Kotlin
String baseUrl = "https://example.com";
DefaultUriBuilderFactory uriBuilderFactory = new DefaultUriBuilderFactory(baseUrl);
URI uri = uriBuilderFactory.uriString("/hotels/{hotel}")
.queryParam("q", "{q}")
.build("Westin", "123");val baseUrl = "https://example.com"
val uriBuilderFactory = DefaultUriBuilderFactory(baseUrl)
val uri = uriBuilderFactory.uriString("/hotels/{hotel}")
.queryParam("q", "{q}")
.build("Westin", "123")URI 解析
Spring MVC および Spring WebFlux
UriComponentsBuilder は 2 つの URI パーサー型をサポートしています。
RFC パーサー — このパーサー型は、URI 文字列が RFC 3986 構文に準拠していることを想定しており、構文からの逸脱は不正として扱います。
WhatWG パーサー — このパーサーは、WhatWG URL 生活水準 (英語) の URL 解析アルゴリズム [GitHub] (英語) に基づいています。これは、予期しない入力のさまざまなケースを寛容に処理します。ブラウザーは、ユーザーが入力した URL を寛容に処理するためにこれを実装します。詳細については、URL Living Standard および URL 解析テストケース [GitHub] (英語) を参照してください。
デフォルトでは、RestClient、WebClient、RestTemplate は RFC パーサー型を使用し、アプリケーションが RFC 構文に準拠した URL テンプレートを提供することを期待します。これを変更するには、いずれかのクライアントで UriBuilderFactory をカスタマイズできます。
アプリケーションとフレームワークは、さらに、ユーザーが提供する URL を解析して、スキーム、ホスト、ポート、パス、クエリなどの URI コンポーネントをインスペクションし、検証するために、独自のニーズに合わせて UriComponentsBuilder に依存する場合があります。このようなコンポーネントは、入力 URL へのリダイレクトの場合やブラウザーへのレスポンスに含まれている場合に、URL をより寛大に処理し、ブラウザーが URI を解析する方法に合わせるために、WhatWG パーサー型を使用することを決定できます。
URI エンコーディング
Spring MVC および Spring WebFlux
UriComponentsBuilder は、2 つのレベルでエンコードオプションを公開します。
UriComponentsBuilder#encode() (Javadoc) : 最初に URI テンプレートを事前にエンコードし、次に展開時に URI 変数を厳密にエンコードします。
UriComponents#encode() (Javadoc) : URI 変数が展開された後、 URI コンポーネントをエンコードします。
どちらのオプションも、非 ASCII 文字と不正な文字をエスケープされたオクテットに置き換えます。ただし、最初のオプションは、URI 変数に表示される予約された意味で文字を置き換えます。
| ";" を検討してください。これはパスでは有効ですが、意味は予約されています。最初のオプションは ";" を置き換えます。URI 変数には "%3B" が含まれますが、URI テンプレートには含まれません。対照的に、2 番目のオプションはパス内の正当な文字であるため、";" を置き換えることはありません。 |
ほとんどの場合、最初のオプションは URI 変数を完全にエンコードされる不透明(OPAQUE)データとして扱うため、期待どおりの結果が得られる可能性があります。2 番目のオプションは、URI 変数に意図的に予約文字が含まれている場合に役立ちます。2 番目のオプションは、URI 変数をまったく展開しない場合にも役立ちます。これは、偶然に URI 変数のように見えるものもエンコードするためです。
次の例では、最初のオプションを使用しています。
Java
Kotlin
URI uri = UriComponentsBuilder.fromPath("/hotel list/{city}")
.queryParam("q", "{q}")
.encode()
.buildAndExpand("New York", "foo+bar")
.toUri();
// Result is "/hotel%20list/New%20York?q=foo%2Bbar"val uri = UriComponentsBuilder.fromPath("/hotel list/{city}")
.queryParam("q", "{q}")
.encode()
.buildAndExpand("New York", "foo+bar")
.toUri()
// Result is "/hotel%20list/New%20York?q=foo%2Bbar"次の例に示すように、URI に直接移動することで、前述の例を短縮できます(エンコードを意味します)。
Java
Kotlin
URI uri = UriComponentsBuilder.fromPath("/hotel list/{city}")
.queryParam("q", "{q}")
.build("New York", "foo+bar");val uri = UriComponentsBuilder.fromPath("/hotel list/{city}")
.queryParam("q", "{q}")
.build("New York", "foo+bar")次の例に示すように、完全な URI テンプレートを使用してさらに短縮できます。
Java
Kotlin
URI uri = UriComponentsBuilder.fromUriString("/hotel list/{city}?q={q}")
.build("New York", "foo+bar");val uri = UriComponentsBuilder.fromUriString("/hotel list/{city}?q={q}")
.build("New York", "foo+bar")WebClient と RestTemplate は、UriBuilderFactory 戦略を通じて内部で URI テンプレートを拡張およびエンコードします。次の例に示すように、どちらもカスタム戦略で構成できます。
Java
Kotlin
String baseUrl = "https://example.com";
DefaultUriBuilderFactory factory = new DefaultUriBuilderFactory(baseUrl)
factory.setEncodingMode(EncodingMode.TEMPLATE_AND_VALUES);
// Customize the RestTemplate..
RestTemplate restTemplate = new RestTemplate();
restTemplate.setUriTemplateHandler(factory);
// Customize the WebClient..
WebClient client = WebClient.builder().uriBuilderFactory(factory).build();val baseUrl = "https://example.com"
val factory = DefaultUriBuilderFactory(baseUrl).apply {
encodingMode = EncodingMode.TEMPLATE_AND_VALUES
}
// Customize the RestTemplate..
val restTemplate = RestTemplate().apply {
uriTemplateHandler = factory
}
// Customize the WebClient..
val client = WebClient.builder().uriBuilderFactory(factory).build()DefaultUriBuilderFactory 実装は、UriComponentsBuilder を内部的に使用して URI テンプレートを展開およびエンコードします。ファクトリとして、以下のエンコードモードのいずれかに基づいて、エンコードへのアプローチを構成する単一の場所を提供します。
TEMPLATE_AND_VALUES: 前のリストの最初のオプションに対応するUriComponentsBuilder#encode()を使用して、URI テンプレートを事前エンコードし、展開時に URI 変数を厳密にエンコードします。VALUES_ONLY: URI テンプレートをエンコードせず、代わりに、UriUtils#encodeUriVariablesを使用して URI 変数をテンプレートに展開する前に URI 変数に厳密なエンコードを適用します。URI_COMPONENT: 前のリストの 2 番目のオプションに対応するUriComponents#encode()を使用して、URI 変数が展開された後に URI コンポーネント値をエンコードします。NONE: エンコードは適用されません。
RestTemplate は、歴史的な理由と下位互換性のために EncodingMode.URI_COMPONENT に設定されています。WebClient は、5.0.x の EncodingMode.URI_COMPONENT から 5.1 の EncodingMode.TEMPLATE_AND_VALUES に変更された DefaultUriBuilderFactory のデフォルト値に依存しています。