我使用WebClient(SpringBoot 2.0.2.RELEASE)发送带有 SOAP 请求的POST,但它缺少" 内容长度"遗留API所需的标头。
是否可以将WebClient配置为包含" 内容长度"头? 在SpringBoot 2.0.1中为 EncoderHttpMessageWriter 解析并引入了Spring Framework Issue,但它似乎不适用于JAXB。
我尝试使用BodyInserters
:
webClient.post().body(BodyInserters.fromObject(request)).exchange();
和syncBody
:
webClient.post().syncBody(request).exchange();
它们都不适用于WebClient
。但是,在使用RestTemplate
时,会设置 Content-Length ,并且API会成功响应
答案 0 :(得分:2)
WebClient
是流客户端,在流完成之前很难设置内容长度。届时,标题将不复存在。如果您使用的是旧版,则可以重用mono(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);
}
我的一位同事(做得好!Max!)提出了更清洁的解决方案,我添加了一些包装代码,以便可以对其进行测试:
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());
答案 1 :(得分:1)
我正在努力解决同样的问题,作为一个丑陋的解决方法,我手动序列化请求(在我的情况下为JSON)并设置长度(Kotlin代码):
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)
}
}
答案 2 :(得分:0)
如果像我们一样应用Sven的colleague(Max)解决方案,您还可以将其调整为适合您的身体作为自定义obj的情况,但是您必须对其进行序列化一次:
String req = objectMapper.writeValueAsString(requestObject)
并将其传递给
webClient.syncBody(req)
请记住,在SpringBoot 2.0.3.RELEASE中,如果将String作为请求传递给webClient,它将作为ContentType标头MediaType.TEXT_PLAIN放置,这会使我们与其他服务的集成失败。我们通过专门设置内容类型标头来解决此问题,例如:
httpHeaders.setContentType(MediaType.APPLICATION_JSON);