Gymterview
middle

Как работает WebClient и чем он отличается от RestTemplate?

WebClient — неблокирующий, реактивный HTTP-клиент из Spring WebFlux, пришедший на замену блокирующему RestTemplate. Начиная со Spring 6.1, появился также RestClient — блокирующий клиент с fluent API.

Эволюция HTTP-клиентов в Spring

Клиент Версия Spring Модель Статус в 2026
RestTemplate Spring 3 (2009) Блокирующий Maintenance mode
WebClient Spring 5 (2017) Реактивный (неблокирующий) Актуален
RestClient Spring 6.1 (2023) Блокирующий, fluent API Рекомендуемый для блокирующего кода

WebClient — базовое использование

Пример
WebClient webClient = WebClient.builder()
    .baseUrl("https://api.example.com")
    .defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
    .build();

// GET — Mono
Mono<User> user = webClient.get()
    .uri("/users/{id}", 1)
    .retrieve()
    .bodyToMono(User.class);

// GET — Flux (список)
Flux<User> users = webClient.get()
    .uri("/users")
    .retrieve()
    .bodyToFlux(User.class);

// POST
Mono<User> created = webClient.post()
    .uri("/users")
    .bodyValue(new CreateUserRequest("John", "john@example.com"))
    .retrieve()
    .bodyToMono(User.class);
Обработка ошибок HTTP
Mono<User> user = webClient.get()
    .uri("/users/{id}", userId)
    .retrieve()
    .onStatus(HttpStatusCode::is4xxClientError, response ->
        response.bodyToMono(ErrorResponse.class)
            .flatMap(error -> Mono.error(new ApiException(error.getMessage()))))
    .onStatus(HttpStatusCode::is5xxServerError, response ->
        Mono.error(new ServiceUnavailableException("Сервис недоступен")))
    .bodyToMono(User.class)
    .retryWhen(Retry.backoff(3, Duration.ofSeconds(1))
        .filter(e -> e instanceof ServiceUnavailableException));
Таймауты и конфигурация
HttpClient httpClient = HttpClient.create()
    .responseTimeout(Duration.ofSeconds(5))
    .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 3000);

WebClient webClient = WebClient.builder()
    .baseUrl("https://api.example.com")
    .clientConnector(new ReactorClientHttpConnector(httpClient))
    .filter(ExchangeFilterFunction.ofRequestProcessor(request -> {
        log.info("Request: {} {}", request.method(), request.url());
        return Mono.just(request);
    }))
    .build();

RestClient (Spring 6.1+) — блокирующая альтернатива

Пример
RestClient restClient = RestClient.builder()
    .baseUrl("https://api.example.com")
    .build();

User user = restClient.get()
    .uri("/users/{id}", 1)
    .retrieve()
    .body(User.class);

Сравнение

Критерий RestTemplate WebClient RestClient
Блокирующий Да Нет Да
API стиль Методы (getForObject) Fluent chain Fluent chain
Streaming Нет Да Нет
Зависимость spring-web spring-webflux + reactor-netty spring-web
Тестирование MockRestServiceServer MockWebServer MockRestServiceServer

Частые ошибки

  • Создавать новый WebClient на каждый запрос — WebClient потокобезопасный, создавайте один раз
  • Вызывать .block() в реактивном контексте — deadlock; допустим только в блокирующем коде
  • Не обрабатывать HTTP-ошибки — без onStatus WebClient бросает неинформативное исключение
  • Использовать WebClient только потому, что RestTemplate deprecated — для блокирующего кода лучше RestClient

Как используется в 2026

  • RestClient — стандартный HTTP-клиент для Spring MVC (Spring 6.1+)
  • WebClient — для реактивных приложений (WebFlux) и streaming
  • RestTemplate встречается в legacy-коде
  • Spring HTTP Interface (@HttpExchange) работает и с WebClient, и с RestClient — декларативный стиль

На собеседовании: знайте три клиента (RestTemplate, WebClient, RestClient) и когда какой использовать. Частая ошибка — говорить «RestTemplate deprecated, используйте WebClient» без нюансов. RestTemplate в maintenance mode, но для блокирующего кода лучше RestClient, а не WebClient с .block().