首页 文章

缺少使用WebClient发送POST请求的Content-Length标头(SpringBoot 2.0.2.RELEASE)

提问于
浏览
2

我正在使用WebClient(SpringBoot 2.0.2.RELEASE)发送带有 SOAP 请求的POST,但缺少遗留API所需的“ Content-Length ”标头 .

是否可以将WebClient配置为包含“ Content-Length ” Headers ?在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会成功响应

3 回答

  • 2

    WebClient 是一个流式客户端,在流完成之前设置内容长度很困难 . 到那时, Headers 早已不复存在 . 如果使用legacy,则可以重新使用单声道(可以重复使用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

    我正在努力解决同样的问题,作为一个丑陋的解决方法,我手动序列化请求(在我的情况下为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)
        }
    }
    
  • 0

    如果您像我们一样应用Sven的同事(Max)解决方案,您也可以根据您的身体作为自定义对象的情况进行调整,但您必须将其序列化一次:

    String req = objectMapper.writeValueAsString(requestObject)
    

    并传递给

    webClient.syncBody(req)
    

    请记住,使用SpringBoot 2.0.3.RELEASE,如果您将String作为请求传递给webClient,它将作为ContentType标头MediaType.TEXT_PLAIN,并使我们与其他服务的集成失败 . 我们通过设置具体的内容类型 Headers 来修复它:

    httpHeaders.setContentType(MediaType.APPLICATION_JSON);
    

相关问题