[Spring Webflx] 19. 예외처리 : onErrorResume, ErrorWebExceptionHandler

y001·2025년 5월 8일

Reactive Programming

목록 보기
27/30
post-thumbnail

1. onErrorResume Operator를 이용한 예외 처리

개요

onErrorResume은 리액티브 스트림에서 에러가 발생했을 때, 해당 에러를 Downstream으로 전파하지 않고 대체 Publisher를 통해 정상적인 흐름을 이어가는 방법이다.
특정 예외에 대해 분기 처리하거나, 에러 내용을 감싸서 새로운 응답을 만들 수 있다.

주요 특징

  • 에러 발생 시 지정한 예외 타입에 따라 다른 흐름을 선택할 수 있음
  • 일반적으로 각 시퀀스 내에서 국소적으로 사용
  • 가벼운 예외 처리에 적합

예제 코드 (수정 및 개선됨)

@Component
public class BookHandler {
    public Mono<ServerResponse> createBook(ServerRequest request) {
        return request.bodyToMono(BookDto.Post.class)
            .doOnNext(post -> validator.validate(post)) // 오타 수정
            .flatMap(book -> ServerResponse
                .created(URI.create("/v1/books/" + book.getBookId()))
                .build()
            )
            .onErrorResume(BusinessLogicException.class, error -> ServerResponse
                .badRequest()
                .bodyValue(new ErrorResponse(HttpStatus.BAD_REQUEST, error.getMessage()))
            )
            .onErrorResume(Exception.class, error -> ServerResponse
                .unprocessableEntity()
                .bodyValue(new ErrorResponse(HttpStatus.UNPROCESSABLE_ENTITY, error.getMessage()))
            );
    }
}

장점

  • 시퀀스 내에서 바로 처리할 수 있어 직관적
  • 간단한 예외 대응 시 매우 편리

단점

  • 시퀀스가 많아지면 각 체인마다 onErrorResume을 추가해야 하므로 중복 코드 증가
  • 일관된 예외 처리가 어려움

2. ErrorWebExceptionHandler를 이용한 글로벌 예외 처리

개요

Spring WebFlux는 전역 예외 처리기로 ErrorWebExceptionHandler 인터페이스를 제공한다.
이 방식을 사용하면 모든 에러를 하나의 컴포넌트에서 공통 처리할 수 있어, 코드 중복을 줄이고 예외 처리 로직을 일원화할 수 있다.

등록 예시

@Component
@Order(-2) // 기본 WebExceptionHandler보다 우선순위를 높게 설정
public class GlobalExceptionHandler implements ErrorWebExceptionHandler {
    @Override
    public Mono<Void> handle(ServerWebExchange exchange, Throwable ex) {
        HttpStatus status;
        String message;

        if (ex instanceof BusinessLogicException) {
            status = HttpStatus.BAD_REQUEST;
            message = ex.getMessage();
        } else {
            status = HttpStatus.INTERNAL_SERVER_ERROR;
            message = "Internal Server Error";
        }

        ErrorResponse errorResponse = new ErrorResponse(status, message);
        byte[] bytes = serializeToJsonBytes(errorResponse); // JSON 직렬화
        DataBuffer buffer = exchange.getResponse().bufferFactory().wrap(bytes);

        exchange.getResponse().setStatusCode(status);
        exchange.getResponse().getHeaders().setContentType(MediaType.APPLICATION_JSON);
        return exchange.getResponse().writeWith(Mono.just(buffer));
    }
}

장점

  • 중앙 집중식 예외 처리 가능
  • 모든 Handler에서 동일한 정책으로 처리 가능
  • 코드 중복 제거, 유지보수성 향상

단점

  • 세부적인 흐름 안에서 유연하게 대체 Publisher를 구성하기 어려움
  • 비동기 흐름의 컨텍스트에서 예외를 구분하기 어려운 경우도 있음

결론

비교 항목onErrorResumeErrorWebExceptionHandler
사용 위치개별 시퀀스 내부전역 (모든 요청)
장점직관적, 유연한 흐름 제어일관된 예외 처리, 중복 제거
단점시퀀스마다 중복 처리 필요흐름에 따른 유연한 대체 처리 어려움
적합한 경우특정 흐름에 대한 예외 보정 필요할 때전체 시스템에 일관된 에러 응답 필요할 때

둘 다 상황에 따라 병행 사용할 수 있으며, 전역 핸들러로 대부분의 예외를 처리하되, 예외적으로 흐름 복구가 필요한 경우에만 onErrorResume을 사용하는 방식이 일반적이다.

0개의 댓글