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)
1URI テンプレートを使用した静的ファクトリメソッド。
2URI コンポーネントを追加または置換します。
3URI テンプレートと URI 変数をエンコードするようリクエストします。
4UriComponents をビルドします。
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)
1URI テンプレートを使用した静的ファクトリメソッド。
2URI コンポーネントを追加または置換します。
3URI テンプレートと URI 変数をエンコードするようリクエストします。
4UriComponents をビルドします。
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 パーサー型をサポートしています。

  1. RFC パーサー — このパーサー型は、URI 文字列が RFC 3986 構文に準拠していることを想定しており、構文からの逸脱は不正として扱います。

  2. WhatWG パーサー — このパーサーは、WhatWG URL 生活水準 (英語) URL 解析アルゴリズム [GitHub] (英語) に基づいています。これは、予期しない入力のさまざまなケースを寛容に処理します。ブラウザーは、ユーザーが入力した URL を寛容に処理するためにこれを実装します。詳細については、URL Living Standard および URL 解析テストケース [GitHub] (英語) を参照してください。

デフォルトでは、RestClientWebClientRestTemplate は RFC パーサー型を使用し、アプリケーションが RFC 構文に準拠した URL テンプレートを提供することを期待します。これを変更するには、いずれかのクライアントで UriBuilderFactory をカスタマイズできます。

アプリケーションとフレームワークは、さらに、ユーザーが提供する URL を解析して、スキーム、ホスト、ポート、パス、クエリなどの URI コンポーネントをインスペクションし、検証するために、独自のニーズに合わせて UriComponentsBuilder に依存する場合があります。このようなコンポーネントは、入力 URL へのリダイレクトの場合やブラウザーへのレスポンスに含まれている場合に、URL をより寛大に処理し、ブラウザーが URI を解析する方法に合わせるために、WhatWG パーサー型を使用することを決定できます。

URI エンコーディング

Spring MVC および Spring WebFlux

UriComponentsBuilder は、2 つのレベルでエンコードオプションを公開します。

どちらのオプションも、非 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 のデフォルト値に依存しています。