WebClient 예외 처리 개념 및 원리

지난번 스프링 부트에서 RestTemplate을 사용한 예외 처리를 살펴보았습니다. 이번 포스팅에서는 RestTemplate과 WebClient의 차이점과 각 도구에서 예외를 처리하는 방법을 알아봅니다. RestTemplate은 동기식으로, WebClient는 비동기식으로 HTTP 요청을 처리하며, 예외 처리 방식에도 차이가 있습니다. 이 글을 통해 두 가지 도구의 예외 처리 방법을 쉽게 이해할 수 있습니다.
WebClient 예외 처리 개념 및 원리
Photo by Tai Bui / Unsplash

On this page

지난번 스프링부트 RestTemplate 예외처리를 알아보았는데요. RestTemplateWebClient는 HTTP 요청을 보내기 위한 두 가지 다른 도구이며, 예외 처리 방식에서도 차이가 있습니다. RestTemplate은 동기식 HTTP 요청을 처리하고, WebClient는 비동기식으로 HTTP 요청을 처리합니다. 두 가지 도구 모두 예외를 발생시키지만, 비동기식인 WebClient의 예외 처리는 약간 다릅니다.

WebClient 예외 처리 개념 및 원리

WebClient 비동기적으로 요청을 처리하기 때문에 예외 처리도 비동기 방식으로 처리해야 합니다. 이를 위해 onStatus, onErrorMap, doOnError 등의 메서드를 사용하여 예외를 처리할 수 있습니다.

WebClient 설정 및 예외 처리

WebClient를 사용할 때, 예외 처리를 위한 방법은 두 가지가 있습니다:

  1. 전역 예외 처리기 사용: @ControllerAdvice@ExceptionHandler를 사용하여 전역적으로 예외를 처리합니다.
  2. WebClient 요청 내에서 예외 처리: WebClient 요청 자체에서 예외를 처리합니다.

전역 예외 처리기 설정

전역 예외 처리기를 사용하여 WebClient에서 발생한 예외를 처리할 수 있습니다. 이 방법은 주로 API 응답을 통합적으로 관리할 때 유용합니다.

예제 코드

import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.reactive.function.client.WebClientResponseException;

@ControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(WebClientResponseException.class)
    public ResponseEntity<String> handleWebClientResponseException(WebClientResponseException ex) {
        String responseBody = ex.getResponseBodyAsString();
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(ex.getHeaders().getContentType());
        return new ResponseEntity<>(responseBody, headers, ex.getStatusCode());
    }
}

WebClient 요청 내에서 예외 처리

WebClient 요청 자체에서 예외를 처리할 수 있습니다. 이를 통해 요청을 보낼 때마다 개별적으로 예외를 처리할 수 있습니다.

예제 코드

import org.springframework.web.reactive.function.client.WebClient;
import org.springframework.web.reactive.function.client.WebClientResponseException;
import reactor.core.publisher.Mono;

public class WebClientService {

    private final WebClient webClient;

    public WebClientService(WebClient.Builder webClientBuilder) {
        this.webClient = webClientBuilder.baseUrl("<http://your-api-server-url>").build();
    }

    public Mono<String> requestAction(String requestActionSetDtoJson) {
        return webClient.post()
                .uri("/action/requestAction")
                .bodyValue(requestActionSetDtoJson)
                .retrieve()
                .onStatus(HttpStatus::is4xxClientError, clientResponse ->
                        clientResponse.bodyToMono(String.class)
                                .flatMap(body -> Mono.error(new WebClientResponseException(
                                        clientResponse.rawStatusCode(),
                                        clientResponse.statusCode().getReasonPhrase(),
                                        clientResponse.headers().asHttpHeaders(),
                                        body.getBytes(),
                                        null
                                )))
                )
                .onStatus(HttpStatus::is5xxServerError, clientResponse ->
                        clientResponse.bodyToMono(String.class)
                                .flatMap(body -> Mono.error(new WebClientResponseException(
                                        clientResponse.rawStatusCode(),
                                        clientResponse.statusCode().getReasonPhrase(),
                                        clientResponse.headers().asHttpHeaders(),
                                        body.getBytes(),
                                        null
                                )))
                )
                .bodyToMono(String.class)
                .doOnError(WebClientResponseException.class, ex -> {
                    // 추가적인 로깅이나 예외 처리
                    log.error("WebClientResponseException: ", ex);
                });
    }
}

WebClient와 RestTemplate의 차이

  • 동기/비동기: RestTemplate은 동기식으로 작동하고, WebClient는 비동기식으로 작동합니다.
  • 예외 처리: RestTemplate은 일반적인 예외 처리 방법을 사용하고, WebClient는 비동기식 예외 처리 방법을 사용합니다.
  • 기능 확장성:*WebClient는 더 많은 기능을 제공하고, 비동기적이고 반응형 프로그래밍을 지원합니다.

결론

WebClientRestTemplate 모두 예외 처리를 지원하지만, 사용 방법이 다릅니다. WebClient는 비동기 방식으로 작동하므로 예외 처리도 비동기적으로 처리해야 합니다. 전역 예외 처리기를 사용하거나 개별 요청 내에서 예외를 처리하여 원하는 방식으로 예외를 처리할 수 있습니다.

이제 여러분도 WebClientRestTemplate를 활용하여 예외를 깔끔하게 처리할 수 있을 거예요. 도움이 필요하면 언제든지 댓글로 질문해 주세요! Happy coding! 😊

Subscribe to Keun's Story newsletter and stay updated.

Don't miss anything. Get all the latest posts delivered straight to your inbox. It's free!
Great! Check your inbox and click the link to confirm your subscription.
Error! Please enter a valid email address!