缺少 Content-Length header 使用 WebClient 发送 POST 请求 (SpringBoot 2.0.2.RELEASE)
Missing Content-Length header sending POST request with WebClient (SpringBoot 2.0.2.RELEASE)
我正在使用 WebClient (SpringBoot 2.0.2.RELEASE) 发送带有 SOAP 请求的 POST,但它丢失了“Content-Length" header 遗留 API 所要求的。
是否可以将 WebClient 配置为包含“Content-Length”header?
在 SpringBoot 2.0.1 中为 EncoderHttpMessageWriter 解决并引入了 Spring Framework Issue,但它似乎不适用于 JAXB。
我尝试使用 BodyInserters
:
webClient.post().body(BodyInserters.fromObject(request)).exchange();
和syncBody
:
webClient.post().syncBody(request).exchange();
None 他们为 WebClient
工作。但是,当使用 RestTemplate
时,会设置 Content-Length 并且 API 会成功响应
我正在努力解决同样的问题,作为一个丑陋的解决方法,我正在手动序列化请求(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)
}
}
WebClient
是一个流媒体客户端,在流结束之前设置内容长度有点困难。到那时 headers 早已不复存在。如果你使用旧版,你可以 re-use 你的单声道(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());
如果您像我们一样应用 Sven 的同事 (Max) 解决方案,您也可以将其调整为适用于 body 作为自定义对象但必须序列化一次的情况:
String req = objectMapper.writeValueAsString(requestObject)
并将其传递给
webClient.syncBody(req)
请记住,使用 SpringBoot 2.0.3.RELEASE,如果您将字符串作为请求传递给 webClient,它将作为 ContentType header MediaType.TEXT_PLAIN 进行处理我们与其他服务的整合失败。我们通过专门设置内容类型 header 来解决这个问题:
httpHeaders.setContentType(MediaType.APPLICATION_JSON);
我正在使用 WebClient (SpringBoot 2.0.2.RELEASE) 发送带有 SOAP 请求的 POST,但它丢失了“Content-Length" header 遗留 API 所要求的。
是否可以将 WebClient 配置为包含“Content-Length”header? 在 SpringBoot 2.0.1 中为 EncoderHttpMessageWriter 解决并引入了 Spring Framework Issue,但它似乎不适用于 JAXB。
我尝试使用 BodyInserters
:
webClient.post().body(BodyInserters.fromObject(request)).exchange();
和syncBody
:
webClient.post().syncBody(request).exchange();
None 他们为 WebClient
工作。但是,当使用 RestTemplate
时,会设置 Content-Length 并且 API 会成功响应
我正在努力解决同样的问题,作为一个丑陋的解决方法,我正在手动序列化请求(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)
}
}
WebClient
是一个流媒体客户端,在流结束之前设置内容长度有点困难。到那时 headers 早已不复存在。如果你使用旧版,你可以 re-use 你的单声道(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());
如果您像我们一样应用 Sven 的同事 (Max) 解决方案,您也可以将其调整为适用于 body 作为自定义对象但必须序列化一次的情况:
String req = objectMapper.writeValueAsString(requestObject)
并将其传递给
webClient.syncBody(req)
请记住,使用 SpringBoot 2.0.3.RELEASE,如果您将字符串作为请求传递给 webClient,它将作为 ContentType header MediaType.TEXT_PLAIN 进行处理我们与其他服务的整合失败。我们通过专门设置内容类型 header 来解决这个问题:
httpHeaders.setContentType(MediaType.APPLICATION_JSON);