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
のデフォルト値に依存しています。