Есть ли способ предоставить поток в тело веб-клиента в виде данных формы?

#java #spring-webflux #project-reactor

#java #spring-webflux #проект-реактор

Вопрос:

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

 private Mono<MyDataType> getMyDataType() {
    return WebClient.builder().build().post()
            .uri(MY_URI)
            .contentType(MediaType.APPLICATION_FORM_URLENCODED)
            .body(BodyInserters.fromFormData(getFormData()))
            .exchange()
            .flatMap(clientResponse -> clientResponse.bodyToMono(MyDataType.class));
}

private MultiValueMap<String, String> getFormData() {
    MultiValueMap<String, String> credentials = new LinkedMultiValueMap<>();
    credentials.add("login", readLoginStringFromDiskAsString);
    credentials.add("password", readPasswordStringFromDiskAsString);
}
  

Однако мои read* функции, как вы можете видеть, просты в блокировке Files.readAllBytes , как и в любом другом приложении.
Я хотел бы перевести это чтение с диска на что-то более асинхронное, например, использовать DataBufferUtils или что-то подобное. Проблема в том, что Spring предоставляет только одну реализацию fromFormData fromFormData(MultiValueMap<String, String> formData) .

Есть ли способ на самом деле достичь этого?

Ответ №1:

Вы могли бы изменить свой getFormData метод, чтобы возвращать Mono<MultiValueMap<String, String>> и отображать его результат для асинхронного доступа к учетным данным

 private Mono<MultiValueMap<String, String>> getFormDataNonBlocking() {
    //asynchronous nonblocking reading of the credentials
}

private Mono<MyDataType> getMyDataType() {
    return getFormDataNonBlocking()
            .flatMap(credentials -> WebClient.builder()
                    .build()
                    .post()
                    .uri(MY_URI)
                    .contentType(MediaType.APPLICATION_FORM_URLENCODED)
                    .body(BodyInserters.fromFormData(credentials))
                    .exchange()
                    .flatMap(clientResponse -> clientResponse.bodyToMono(MyDataType.class)));
}
  

Есть одно замечание. Вы не должны создавать новый WebClient для каждого запроса. Используйте предопределенные WebClient.Builder компоненты из Spring Boot или повторно используйте один собственный экземпляр.

Комментарии:

1. К сожалению, это, вероятно, будет не Mono<MultiValueMap<String, String>> , а MultiValueMap<String, Flux<String>> , с которым сложно работать.