Reputation: 394
I'm using WebClient (SpringBoot 2.0.2.RELEASE) to send a POST with SOAP request, but it is missing "Content-Length" header required by the legacy API.
Is it possible to configure WebClient to include "Content-Length" header? There is an Spring Framework Issue resolved and introduced for EncoderHttpMessageWriter in SpringBoot 2.0.1, but it seems not to work for JAXB.
I tried to use BodyInserters
:
webClient.post().body(BodyInserters.fromObject(request)).exchange();
and syncBody
:
webClient.post().syncBody(request).exchange();
None of them worked for WebClient
. Though, when RestTemplate
is used, Content-Length is set and API responds with success
Upvotes: 4
Views: 15359
Reputation: 934
If you apply Sven's colleague(Max) solution like we did you can also adapt it for cases like your body being a custom obj but you have to serialize it once:
String req = objectMapper.writeValueAsString(requestObject)
and passed that to
webClient.syncBody(req)
Keep in mind that with SpringBoot 2.0.3.RELEASE, if you'll pass a String to webClient as a request, it will put as ContentType header MediaType.TEXT_PLAIN and that made our integration with other service to fail. We fixed that by setting specifically content type header like this:
httpHeaders.setContentType(MediaType.APPLICATION_JSON);
Upvotes: 3
Reputation: 952
WebClient
is a streaming client and it's kind of difficult to set the content length until the stream has finished. By then the headers are long gone. If you work with legacy, you can re-use your mono (Mono/Flux can be reused, Java streams not) and check the length.
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);
}
A colleague (well done Max!) of mine came up with cleaner solution, I added some wrapping code so it can be tested:
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());
Upvotes: 2
Reputation: 362
I am struggling with the same problem, as an ugly work-around I am manually serializing the request (JSON in my case) and setting the length (Kotlin code):
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)
}
}
Upvotes: 4