Spring Web Reactive | 1. Spring WebFlux | 1.6. URI 링크

Web MVC

이 섹션에서는 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

UriComponentsBuilderUriBuilder를 구현하고 있다. UriBuilderFactory를 사용하여 UriBuilder를 만들 수 있다. UriBuilderFactoryUriBuilder는 기본 URL 인코딩 설정 및 기타 세부 정보 등의 공유 구성에 따라 URI 템플릿에서 URI를 구축하는 플러그 가능한 메커니즘을 제공한다.

RestTemplate 그리고 WebClientUriBuilderFactory으로 구성하여 URI의 준비를 커스터마이징할 수 있다. DefaultUriBuilderFactoryUriComponentsBuilder를 내부적으로 사용하고, 공유 구성 옵션을 공개된 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개의 레벨에서 인코딩 옵션을 제공한다.

두 옵션 모두, 비 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")

WebClientRestTemplateUriBuilderFactory 전략에 의해 내부적으로 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에 설정되어 있다. WebClientDefaultUriBuilderFactory 기본값에 의존하고 있다. 이것은 5.0.x의 EncodingMode.URI_COMPONENT에서 5.1의 EncodingMode.TEMPLATE_AND_VALUES으로 변경되었다.




최종 수정 : 2021-04-12