spring 2.6.3 기준으로 작성된 글입니다.
이번 포스팅에서는 spring의 RestTemplate로 한글이 담긴 문자열을 포함한 Post형식의 Request를 보낼 때 한글이 깨지는 현상의 해결 방법에 대해 작성해보려고 합니다.
우선 문제 상황에 대해 살펴보겠습니다.
안녕! hi!이라는 한글과 영어가 포함된 간단한 문자열을 보내는 테스트 코드를 작성해보겠습니다.
@SpringBootTest
public class Test {
@Autowired RestTemplate restTemplate;
@org.junit.jupiter.api.Test
void test() {
HttpHeaders httpHeaders = new HttpHeaders();
String str = "안녕! hi!";
HttpEntity<String> entity = new HttpEntity<>(str, httpHeaders);
restTemplate.exchange("http://localhost:8080/hi", HttpMethod.POST, entity, String.class);
}
}
@WebServlet(urlPatterns = "/hi")
public class IndexController extends HttpServlet {
@Override
public void service(HttpServletRequest request, HttpServletResponse response) throws IOException {
ServletInputStream inputStream = request.getInputStream();
System.out.println(StreamUtils.copyToString(inputStream, StandardCharsets.UTF_8));
}
}

위의 사진처럼 안녕을 제대로 출력하지 못하는 것을 볼 수 있습니다.
이는 문제의 원인은 RestTemplate가 String을 인코딩할 때 사용하는 StringHttpMessageConverter에 있습니다.

RestTemplate의 생성자에 들어가 보시면 기본적으로 StringHttpMessageConverter라는 객체를 messageConverters에 추가함을 알 수 있습니다.

그런데 이때 StringHttpMessageConverter의 Default Charset이 ISO-8859-1이고 이를 이용해 한글을 인코딩하기 때문에 한글이 깨지는 현상이 발생하게 됩니다.
제가 찾아본 해결 방법으로는 크게 두 가지가 있는데 모두 알아보겠습니다.
첫 번째로는 RestTemplate에 Custom StringHttpMessageConverter를 추가하는 방법입니다.
위의 사진을 보시면 StringHttpMessageConverter는 defaultCharset을 인자로 받는 생성자가 존재합니다.
따라서 UTF-8을 넣어 객체를 만들고, 이를 RestTemplate의 messageConverters 리스트 안에 추가해줍니다.
@Bean
public RestTemplate restTemplate() {
RestTemplate restTemplate = new RestTemplate();
restTemplate.getMessageConverters()
.add(0, new StringHttpMessageConverter(StandardCharsets.UTF_8));
return restTemplate;
}
이때 리스트의 첫 번째 위치로 추가시키는 이유는 기존에 존재하는 StringHttpMessageConverter 때문입니다.
만약 맨 뒤에 추가하게 되면 기존의 default로 생성된 StringHttpMessageConverter의 ISO-8859-1로 인코딩하게 되어 같은 결과가 나타납니다.
두 번째로는 기존에 존재하는 StringHttpMessageConverter를 추가해주는 방법이 있습니다.
사실 Springboot에는 첫 번째 방법처럼 객체를 새로 만들지 않아도 StringHttpMessageConverter가 빈으로 등록되어 있습니다.
그 부분은 HttpMessageConvertersAutoConfiguration에서 확인할 수 있습니다.

이때 server.sevlet.encoding에 대한 properties를 binding 해줌을 볼 수 있습니다.
따라서 application.properties에 다음과 같은 property를 추가하고 RestTemplate에 추가시켜줍니다.
server.servlet.encoding.charset=UTF-8
server.servlet.encoding에 대한 여러 설정에 대해 대해 알고 싶으시다면 이곳에서 확인해주세요.
@Bean
public RestTemplate restTemplate(StringHttpMessageConverter stringHttpMessageConverter) {
RestTemplate restTemplate = new RestTemplate();
restTemplate.getMessageConverters().add(0, stringHttpMessageConverter);
return restTemplate;
}
또는 새로운 messageConverters 리스트를 만들어서 setter를 통해 추가해줄 수도 있습니다.
@Bean
public RestTemplate restTemplate(StringHttpMessageConverter stringHttpMessageConverter) {
RestTemplate restTemplate = new RestTemplate();
List<HttpMessageConverter<?>> messageConverters = List.of(stringHttpMessageConverter);
restTemplate.setMessageConverters(messageConverters);
return restTemplate;
}
다만 이 경우 기존의 messageConverters를 아예 지워버리기 때문에 다른 messageConverter를 필요에 따라 추가해주셔야 합니다.

이후 다시 테스트를 해보면 잘 자동함을 볼 수 있습니다.
https://cornswrold.tistory.com/402
https://stackoverflow.com/questions/29392422/how-can-i-tell-resttemplate-to-post-with-utf-8-encoding