1.6. URI 링크

편집일시: 2021-04-12 14:23 조회수: 220 댓글수: 0
[Web MVC](https://docs.spring.io/spring-framework/docs/current/reference/html/web.html#mvc-uri-building) 이 섹션에서는 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`](https://docs.spring.io/spring-framework/docs/current/reference/html/web-reactive.html#web-uricomponents)는 `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()`](https://docs.spring.io/spring-framework/docs/5.3.5/javadoc-api/org/springframework/web/util/UriComponentsBuilder.html#encode--) : 먼저 URI 템플릿을 사전에 인코딩한 다음 배포시 URI 변수를 엄격하게 인코딩한다. - [`UriComponents#encode()`](https://docs.spring.io/spring-framework/docs/5.3.5/javadoc-api/org/springframework/web/util/UriComponents.html#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`으로 변경되었다.

다음 글 : 1.7. CORS