공공데이터 포탈에서 데이터를 조회하고 그에 따른 데이터를 받기 위해 어떠한 방식으로 API요청을 보내고 데이터를 받는 것이 성능적인 측면에서 더 좋은 성능을 낼 수 있을지 고찰해보았다.
HTTP 통신에서 사용하는 템플릿으로 HTTP 서버와의 단순한 통신을 위한 함수를 제공하는 클래스다.
웹에서 API를 호출하기 위해 사용하는 Http Client 모듈 중 하나로 기존의 동기식 API 방식 뿐만 아니라 Non-Blocking 및 비동기 방식을 지원한다.
공식문서에 따르면 확장성이 넓은 WebClient를 RestTemplate 대신 사용하라고 명시되어 있다.
WebClient를 사용하기 위해 WebClient에 대한 설정을 해주었다.
@Configuration
public class WebClientConfig {
@Value(value = "${base-url}")
private String baseUrl;
@Bean
public WebClient webClient() {
HttpClient httpClient = HttpClient.create()
//Connection Timeout 설정
.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 10000)
//Read and Write Timeout 설정
.doOnConnected(conn -> conn
.addHandlerLast(new ReadTimeoutHandler(10))
.addHandlerLast(new WriteTimeoutHandler(10)))
//응답 Timeout 설정
.responseTimeout(Duration.ofSeconds(2));
return WebClient.builder()
.baseUrl(baseUrl)
//Spring WebFlux에서 Application Memory문제 피하기 위해 in-memory buffer 값이 256KB로 기본 설정
//256KB보다 큰 HTTP 메시지 처리 시도 -> DataBufferLimitException 에러 발생 : in-memory buffer 값 늘리기
.codecs(configurer -> {
configurer.defaultCodecs().maxInMemorySize(1024 * 1024); //1MB
})
.clientConnector(new ReactorClientHttpConnector(httpClient))
.defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
.build();
}
}
여러 WebClient에 대한 글과 공식문서를 참고하여 위와 같이 WebClient를 설정하였다.
@Service
@RequiredArgsConstructor
public class OpenApiService {
@Value(value = "${secret}")
private String secretKey;
private final WebClient webClient;
private final String path = "/~/해당 path data";
//POST API 요청 예시
public StatusDto getApiData(String param){
MultiValueMap<String, Object> formData = new LinkedMultiValueMap<>();
formData.add("param", param);
return webClient.post()
.uri(uriBuilder -> uriBuilder.path(path + "/add-path").queryParam("serviceKey", secretKey).build())
.bodyValue(formData)
.retrieve()
// 에러가 발생 했을 경우 Exception 발생
.onStatus(HttpStatus::isError, clientResponse ->
clientResponse.bodyToMono(Error.class).flatMap(error -> Mono.error(
new AbleRuntimeException(error.getMessage())
)))
.bodyToMono(StatusDto.class)
.block();
}
}
formData에 param으로 보낼 데이터를 넣고, POST방식으로 WebClient를 사용한 코드이다.
WebClient와 RestTemplate의 가장 큰 차이점은 WebClient는 Non-Blocking방식이고, RestTemplate Blocking방식인 것이지 않을까 생각한다. 또한 현재 공식문서에서는 RestTemplate보다 WebClinet의 사용을 권장하고 있기 때문에 WebClient를 사용하여 외부 API를 호출하는 것이 더 좋을 것이라 생각한다.