본문 바로가기
Issue

[Issue] UriComponentsBuilder Encoding [특수문자, + 예약어, 이중인코딩 방지]

by 잭피 2021. 11. 2.

안녕하세요~ 잭코딩입니다!

RestTemplate, WebClient GET 방식 호출 시, 발생했던 인코딩 이슈를 정리해보려고 합니다

 


Front에서 받은 데이터를 한번 가공해서 GET 방식으로 외부 API를 호출할 때, 인코딩 이슈가 발생했습니다

 

글쓴이는 WebClient GET 방식을 사용했습니다

@Override
public Mono<Map> get(URI uri) {
	return WebClient.builder().build()
                    .get()
                    .uri(uri)
                    .accept(MediaType.APPLICATION_JSON)
                    .retrieve()
                    .bodyToMono(Map.class)
                    .retry(2);
    }
참고로 RestTemplate, WebClient는
URI 타입으로 받으면 인코딩을 진행하지 않고,
String 값으로 받으면 한번 더 인코딩을 진행하여 호출합니다

 

URI 타입으로 파라미터를 받을거라 호출 전 인코딩을 진행해야 합니다

String encodeUri = UriComponentsBuilder.fromHttpUrl(url)
                .queryParam(KEYWORD, keyword).build().encode().toString();

UriComponentBuilder-encode()를 사용해서 한글과 특수문자를 모두 인코딩해줍니다

 

하지만, 결과는 400 Bad Request가 발생했습니다
'+' 예약어가 인코딩되지 않고 호출되었습니다
자료를 찾아보니 UriComponentBuilder는 공백과 +의 경우 인코딩을 해주지 않습니다

 

 public URI encodePlus(String uri) {
        String encodedUri = uri.contains("+") ? uri.replace("+", "%2B") : uri;
        return UriComponentsBuilder.fromUriString(encodedUri).build(true).toUri();
 }

 

replace를 통해 + 기호를 따로 인코딩해주고 다시 UriComponentsBuilder를 통해 URI 인스턴스로 만들어줬습니다

 

여기서 주의할 점은
UriComponentsBuilder.fromUriString(encodedUri).build(true).toUri() -> build()에 true을 넣어줘야합니다 
build()의 파라미터로 boolean 값이 들어가는데, 현재 문자열이 인코딩이 되었는지를 판단하는 값입니다
기본값이 build(false)이므로 String 값을 한번 더 인코딩을 진행합니다
따라서, build()를 사용하면 %252B로 이중 인코딩되는 현상이 발생합니다

 

 

 

댓글