Как правильно слить / освободить тело ответа от клиента WebFlux? - PullRequest
1 голос
/ 14 апреля 2019

Я использую HTTP-клиент WebFlux из реактивного стека Spring 5 для доступа к внешней службе REST. Я хочу обрабатывать ответы на основе статуса HTTP:

  1. Если статус 2xx, я хочу вернуть Mono с телом ответа с десерилизом.

  2. Если статус 404, я хочу отбросить тело ответа и немедленно вернуть пустое Mono.

  3. Для любого другого статуса я хочу сбросить тело ответа и вернуть ошибку Mono с помощью MyBusinessException.

Мой код выглядит так:

webClient.get()
    .uri("/search")
    .syncBody(request)
    .exchange()
    .flatMap { response ->
        when {
            response.statusCode().is2xxSuccessful -> response.bodyToMono(MyResponse::class.java)
            response.statusCode() == NOT_FOUND -> Mono.empty()
            else -> MyBusinessException().toMono<MyResponse>()
        }
     }

Я не хочу тратить время на получение и обработку тела ответа, когда оно мне не нужно. JavaDoc для exchange() состояний метода

Вы всегда должны использовать один из методов ответа body или entity, чтобы обеспечить освобождение ресурсов.

Как именно мне следует это сделать, если я хочу истощить тело ответа и немедленно вернуть результат?

1 Ответ

1 голос
/ 14 апреля 2019

Удаление ответа необходимо для повторного использования соединения для будущих запросов (т. Е. HTTP keep-alive / постоянные соединения).

Для возврата пустого Mono, которое завершается после слива тела (игнорирование ошибок):

// drain the body
response.body(BodyExtractors.toDataBuffers())
    // release DataBuffers
    .doOnNext(DataBufferUtils::release)
    // ignore errors
    .onErrorResume(exception -> Mono.empty())
    // return an empty Mono
    .then();

Для возврата пустого Mono, который немедленно завершается, и асинхронного слива тела (игнорирование ошибок) в фоновом режиме:

Mono.<Void>empty()
    .doOnSubscribe(s ->
        // drain the body
        response.body(BodyExtractors.toDataBuffers())
            // release DataBuffers
            .doOnNext(DataBufferUtils::release)
            // initiate drain on a separate Scheduler
            .subscribeOn(Schedulers.parallel())
            // subscribe, and ignore errors
            .subscribe())

Я бы все равнорекомендуем первый вариант, поскольку он немедленно освобождает ресурсы и, вероятно, это то, что разработчики WebClient имели в виду при написании и документировании его использования.

Я никогда не использовал второй вариант в производственной системе.поэтому проведите собственное тестирование, чтобы убедиться, что пул http-соединений работает так, как вам нужно.Если вы используете реактор-нетто, вы можете включить ведение журнала отладки на reactor.netty.resources.PooledConnectionProvider, чтобы сравнить два подхода.

...