Spring Boot · 2026-04-10

Spring Boot WebClient로 비동기 외부 API 호출 구현

Spring Boot에서 WebClient를 사용해 비동기 HTTP 호출을 구성하고 Mono/Flux 기반 처리, 오류 대응, 타임아웃·리트라이 전략까지 실무 활용 관점에서 설명

작성일 : 2026-04-10 ㆍ 작성자 : 관리자
post
목차

소개

외부 API와 비동기적으로 통신할 때 WebClient는 가벼우면서도 비동기·논블로킹 방식의 장점을 제공한다. 이 글은 spring webclient 사용법을 중심으로 webclient spring boot 비동기 호출 흐름을 단계별로 설명한다. 처음 접하는 개발자도 이해할 수 있도록 개념부터 코드 예제, 운영 시 고려사항까지 정리한다.

WebClient 기본 개념

WebClient는 리액티브 스택인 Spring WebFlux에서 제공하는 HTTP 클라이언트다. reactive webclient spring boot 환경에서는 Mono와 Flux로 응답을 다룬다. Mono는 0~1개의 값을, Flux는 0~N개의 값을 비동기적으로 전달한다.

언제 WebClient를 선택할까?

  • 동시성 높은 I/O 바운드 작업 처리
  • 스레드 풀 소모를 줄여야 할 때
  • 응답 스트리밍이 필요한 경우

WebClient 설정

WebClient는 빈으로 등록해 재사용하는 것이 좋다. 공통 헤더, 커넥션 타임아웃, 최대 커넥션 수 등을 설정할 수 있다. 다음은 기본적인 Bean 등록 예제다.

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.reactive.function.client.ExchangeStrategies;
import org.springframework.web.reactive.function.client.WebClient;

@Configuration
public class WebClientConfig {

    @Bean
    public WebClient webClient(WebClient.Builder builder) {
        return builder
                .baseUrl("https://api.example.com")
                .defaultHeader("Accept", "application/json")
                .exchangeStrategies(ExchangeStrategies.builder()
                        .codecs(configurer -> configurer.defaultCodecs().maxInMemorySize(16 * 1024 * 1024))
                        .build())
                .build();
    }
}

간단한 비동기 호출 예제

다음 예제는 GET 요청을 비동기적으로 호출해 Mono로 응답을 받는 패턴이다. Controller나 Service에서 바로 사용할 수 있다.

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

@Service
public class ApiService {

    private final WebClient webClient;

    public ApiService(WebClient webClient) {
        this.webClient = webClient;
    }

    public Mono<String> fetchData(String id) {
        return webClient.get()
                .uri(uriBuilder -> uriBuilder.path("/data/{id}").build(id))
                .retrieve()
                .bodyToMono(String.class);
    }
}

Controller에서의 반환

웹 계층에서는 Mono나 Flux를 반환하면 Spring이 자동으로 논블로킹 응답을 처리한다. 동기식 방식으로 변환하려면 block()을 사용하지만, 이는 추천되지 않는다.

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Mono;

@RestController
public class ApiController {

    private final ApiService apiService;

    public ApiController(ApiService apiService) {
        this.apiService = apiService;
    }

    @GetMapping("/proxy/{id}")
    public Mono<String> proxy(@PathVariable String id) {
        return apiService.fetchData(id);
    }
}

오류 처리와 응답 상태 코드 관리

retrieve()는 오류 상태 코드에 대해 WebClientResponseException을 발생시킨다. 상황에 따라 onStatus로 직접 처리하거나, onErrorResume으로 폴백 로직을 적용한다.

return webClient.get()
        .uri("/data/{id}", id)
        .retrieve()
        .onStatus(status -> status.is4xxClientError(), resp -> Mono.error(new RuntimeException("Client error")))
        .bodyToMono(MyDto.class)
        .onErrorResume(e -> Mono.just(new MyDto("fallback")));

타임아웃과 리트라이 전략

네트워크 불안정에 대비해 타임아웃과 리트라이를 설정하는 것이 중요하다. Reactor의 timeout, retryWhen을 활용하면 요청 지연과 일시적 실패에 대응할 수 있다.

import reactor.util.retry.Retry;
import java.time.Duration;

return webClient.get()
        .uri("/data/{id}", id)
        .retrieve()
        .bodyToMono(MyDto.class)
        .timeout(Duration.ofSeconds(3))
        .retryWhen(Retry.backoff(3, Duration.ofMillis(500))
                .filter(throwable -> !(throwable instanceof IllegalArgumentException)));

성능과 운영 고려사항

  • 커넥션 풀 크기와 타임아웃을 환경에 맞게 조정
  • 대용량 응답은 스트리밍(Flux)으로 처리해 메모리 사용 최소화
  • 공통 오류 로직을 필터나 ExchangeFilterFunction으로 중앙화
  • 모니터링을 위해 지표(응답 시간, 실패율)를 수집

예시: 공통 필터 등록

요청/응답 로깅이나 인증 토큰 삽입 등은 ExchangeFilterFunction으로 처리하면 코드 중복을 줄일 수 있다.

import org.springframework.web.reactive.function.client.ExchangeFilterFunction;

@Bean
public WebClient webClient(WebClient.Builder builder) {
    return builder
            .filter(logRequest())
            .build();
}

private ExchangeFilterFunction logRequest() {
    return ExchangeFilterFunction.ofRequestProcessor(clientRequest -> {
        // 로그 처리
        return Mono.just(clientRequest);
    });
}

마무리

spring webclient 사용법을 이해하면 외부 API 연동을 비동기·논블로킹으로 안정적으로 구현할 수 있다. webclient spring boot 비동기 특성을 살려 적절한 오류 처리와 타임아웃 정책을 적용하면 운영 리스크를 낮출 수 있다. 처음에는 Mono/Flux 개념이 낯설 수 있으나, 작은 예제부터 시작해 점진적으로 적용하면 무리가 없다.

spring webclient 사용법 webclient spring boot 비동기 reactive webclient spring boot spring boot webclient webclient 예제 spring reactive webclient 오류처리 webclient timeout