Spring Web Reactive | 1. Spring WebFlux | 1.6. URI 링크
이 섹션에서는 URI를 준비하기 위해 Spring Framework에서 사용 가능한 다양한 옵션에 대해 설명한다.
1.6.1. UriComponents
Spring MVC와 Spring WebFlux
UriComponentsBuilder
는 다음의 예제와 같이 변수를 가지는 URI 템플릿에서 URI를 만들 수 있다.
Java
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)
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
를 가져온다.
위의 예제는 다음의 예제와 같이 하나의 체인에 통합하고, buildAndExpand
으로 줄일 수 있다.
Java
URI uri = UriComponentsBuilder
.fromUriString("https://example.com/hotels/{hotel}")
.queryParam("q", "{q}")
.encode()
.buildAndExpand("Westin", "123")
.toUri();
Kotlin
val uri = UriComponentsBuilder
.fromUriString("https://example.com/hotels/{hotel}")
.queryParam("q", "{q}")
.encode()
.buildAndExpand("Westin", "123")
.toUri()
다음의 예제에서는 URI에 직접 이동하여 (인코딩을 암시하는 것을) 더 생략할 수 있다.
Java
URI uri = UriComponentsBuilder
.fromUriString("https://example.com/hotels/{hotel}")
.queryParam("q", "{q}")
.build("Westin", "123");
Kotlin
val uri = UriComponentsBuilder
.fromUriString("https://example.com/hotels/{hotel}")
.queryParam("q", "{q}")
.build("Westin", "123")
다음의 예와 같이, 완전한 URI 템플릿을 사용하여 더욱 줄일 수 있다.
Java
URI uri = UriComponentsBuilder
.fromUriString("https://example.com/hotels/{hotel}")
.queryParam("q", "{q}")
.build("Westin", "123");
Kotlin
val uri = UriComponentsBuilder
.fromUriString("https://example.com/hotels/{hotel}?q={q}")
.build("Westin", "123")
1.6.2. UriBuilder
Spring MVC와 Spring WebFlux
UriComponentsBuilder
는 UriBuilder
를 구현하고 있다. UriBuilderFactory
를 사용하여 UriBuilder
를 만들 수 있다. UriBuilderFactory
과 UriBuilder
는 기본 URL 인코딩 설정 및 기타 세부 정보 등의 공유 구성에 따라 URI 템플릿에서 URI를 구축하는 플러그 가능한 메커니즘을 제공한다.
RestTemplate
그리고 WebClient
이 UriBuilderFactory
으로 구성하여 URI의 준비를 커스터마이징할 수 있다. DefaultUriBuilderFactory
은 UriComponentsBuilder
를 내부적으로 사용하고, 공유 구성 옵션을 공개된 UriBuilderFactory
의 디폴트 구현이다.
다음의 예제는 RestTemplate
을 구성하는 방법을 보여준다.
Java
// 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);
Kotlin
// 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
// 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();
Kotlin
// 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
String baseUrl = "https://example.com";
DefaultUriBuilderFactory uriBuilderFactory = new DefaultUriBuilderFactory(baseUrl);
URI uri = uriBuilderFactory.uriString("/hotels/{hotel}")
.queryParam("q", "{q}")
.build("Westin", "123");
Kotlin
val baseUrl = "https://example.com"
val uriBuilderFactory = DefaultUriBuilderFactory(baseUrl)
val uri = uriBuilderFactory.uriString("/hotels/{hotel}")
.queryParam("q", "{q}")
.build("Westin", "123")
1.6.3. URI 인코딩
Spring MVC와 Spring WebFlux
UriComponentsBuilder
는 2개의 레벨에서 인코딩 옵션을 제공한다.
UriComponentsBuilder#encode()
: 먼저 URI 템플릿을 사전에 인코딩한 다음 배포시 URI 변수를 엄격하게 인코딩한다.UriComponents#encode()
: URI 변수가 적용한 후에 URI 컴포넌트를 인코딩한다.
두 옵션 모두, 비 ASCII 문자와 잘못된 문자를 이스케이프된 옥텟(octet)으로 변경한다. 단, 첫 번째 옵션은 URI 변수에 표시되는 예약된 의미로 문자를 대체한다.
“;“을 검토해라. 이 경로는 유효하지만, 의미는 예약되어 있다. 첫 번째 옵션은 “;“을 대체한다. URI 변수에는 ‘%3B’가 포함되지만, URI 템플릿에 포함되지 않는다. 대조적으로, 두 번째 옵션은 경로의 정당한 캐릭터이기 때문에 “;“를 대체하지 않는다.
대부분의 경우, 첫 번째 옵션은 URI 변수를 완전히 인코딩되는 불투명(OPAQUE) 데이터로 처리하므로, 원하는 결과를 얻을 수 있다. 두 번째 옵션은 URI 변수에 의도적으로 예약 문자가 포함되어 있는 경우에 유용한다. 두 번째 옵션은 URI 변수를 전혀 배포하지 않는 경우에도 도움이 된다. 이것은 우연히 URI 변수처럼 보이는 것도 인코딩하기 때문이다.
다음 예제에서는 첫 번째 옵션을 사용한다.
Java
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"
Kotlin
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
URI uri = UriComponentsBuilder.fromPath("/hotel list/{city}")
.queryParam("q", "{q}")
.build("New York", "foo+bar");
Kotlin
val uri = UriComponentsBuilder.fromPath("/hotel list/{city}")
.queryParam("q", "{q}")
.build("New York", "foo+bar")
다음의 예와 같이, 완전한 URI 템플릿을 사용하여 더욱 단축 할 수 있다.
Java
URI uri = UriComponentsBuilder.fromUriString("/hotel list/{city}?q={q}")
.build("New York", "foo+bar");
Kotlin
val uri = UriComponentsBuilder.fromUriString("/hotel list/{city}?q={q}")
.build("New York", "foo+bar")
WebClient
와 RestTemplate
는 UriBuilderFactory
전략에 의해 내부적으로 URI 템플릿을 확장하고 인코딩한다. 이 모두 커스텀 전략으로 구성 할 수 있다. 다음 예제와 같이 :
Java
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();
Kotlin
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
: 이전 목록의 두 번째 옵션에 해당하는UriComponents#encode()
를 사용하여 URI 변수가 배포 된 후 URI 구성 요소 값을 인코딩한다.NONE
: 인코딩은 적용되지 않는다.
RestTemplate
는 이전 버전과의 호환성을 위해 EncodingMode.URI_COMPONENT
에 설정되어 있다. WebClient
는 DefaultUriBuilderFactory
기본값에 의존하고 있다. 이것은 5.0.x의 EncodingMode.URI_COMPONENT
에서 5.1의 EncodingMode.TEMPLATE_AND_VALUES
으로 변경되었다.