Отсутствует заголовок Content-Length, отправляющий POST-запрос с WebClient (SpringBoot 2.0.2.RELEASE) - PullRequest
0 голосов
/ 23 мая 2018

Я использую WebClient (SpringBoot 2.0.2.RELEASE) для отправки POST с запросом SOAP , но в нем отсутствует заголовок " Content-Length ", требуемый устаревшимAPI.

Можно ли настроить WebClient для включения заголовка " Content-Length "?Существует Spring Framework Issue , разрешенный и введенный для EncoderHttpMessageWriter в SpringBoot 2.0.1, но, похоже, он не работает для JAXB.

Я пытался использовать BodyInserters:

webClient.post().body(BodyInserters.fromObject(request)).exchange();

и syncBody:

webClient.post().syncBody(request).exchange();

Ни один из них не работал на WebClient.Тем не менее, когда используется RestTemplate, Content-Length устанавливается, и API отвечает успешно

Ответы [ 3 ]

0 голосов
/ 26 июня 2018

WebClient является потоковым клиентом, и довольно сложно установить длину содержимого до завершения потока.К тому времени заголовки давно ушли.Если вы работаете со старым, вы можете повторно использовать свой моно (Mono / Flux можно использовать повторно, потоки Java - нет) и проверить длину.

    public void post() {

    Mono<String> mono = Mono.just("HELLO WORLDZ");

    final String response = WebClient.create("http://httpbin.org")
            .post()
            .uri("/post")
            .header(HttpHeaders.CONTENT_LENGTH,
                    mono.map(s -> String.valueOf(s.getBytes(StandardCharsets.UTF_8).length)).block())
            .body(BodyInserters.fromPublisher(mono, String.class))
            .retrieve()
            .bodyToMono(String.class)
            .block();

    System.out.println(response);

}

Пришел мой коллега (молодец Макс!)В дополнение к более чистому решению, я добавил некоторый код переноса, чтобы его можно было проверить:

    Mono<String> my = Mono.just("HELLO WORLDZZ")
            .flatMap(body -> WebClient.create("http://httpbin.org")
                    .post()
                    .uri("/post")
                    .header(HttpHeaders.CONTENT_LENGTH,
                            String.valueOf(body.getBytes(StandardCharsets.UTF_8).length))
                    .syncBody(body)
                    .retrieve()
                    .bodyToMono(String.class));

    System.out.println(my.block());
0 голосов
/ 05 сентября 2018

Если вы применяете решение коллеги (Макс) Свена, как мы, вы также можете адаптировать его для случаев, когда ваше тело является пользовательским объектом, но вы должны его сериализовать один раз:

String req = objectMapper.writeValueAsString(requestObject)

и передать его

webClient.syncBody(req)

Имейте в виду, что с SpringBoot 2.0.3.RELEASE, если вы передадите String в webClient в качестве запроса, он будет помещен в качестве заголовка ContentType MediaType.TEXT_PLAIN, и это сделало нашу интеграцию с другимислужба потерпеть неудачу.Мы исправили это, настроив заголовок типа контента следующим образом:

httpHeaders.setContentType(MediaType.APPLICATION_JSON);
0 голосов
/ 24 мая 2018

Я борюсь с той же проблемой, что и уродливый обходной путь. Я вручную сериализую запрос (в моем случае JSON) и задаю длину (код Котлина):

open class PostRetrieverWith411ErrorFix(
    private val objectMapper: ObjectMapper
) {

protected fun <T : Any> post(webClient: WebClient, body: Any, responseClass: Class<T>): Mono<T> {
    val bodyJson = objectMapper.writeValueAsString(body)

    return webClient.post()
        .contentType(MediaType.APPLICATION_JSON_UTF8)
        .contentLength(bodyJson.toByteArray(Charset.forName("UTF-8")).size.toLong())
        .syncBody(bodyJson)
        .retrieve()
        .bodyToMono(responseClass)
    }
}
...