You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

WebClient添加自定义Header后抛出连接提前关闭异常求助

问题

以下是我编写的代码:

ObjectMapper mapper = new ObjectMapper();
Consumer<HttpHeaders> headersConsumer = headers -> headers.addAll(httpHeaders);
var map = mapper.readValue(payload, Map.class);
var ref = new AtomicReference<ClientResponse>();
var responseMono = webClient
                  .post()
                  .uri(uri)
                  .headers(headersConsumer)
                  .body(Mono.just(map), Map.class)
                  .exchangeToMono(response -> {
                     ref.set(response);
                     if (response.statusCode().equals(HttpStatus.OK)) {
                        return response.bodyToMono(String.class);
                     }
                     else {
                        return response.createException().flatMap(Mono::error);
                     }
             });
var body = responseMono.block();

移除headersConsumer时代码正常运行,但传入该消费者后抛出异常:

WebClientRequestException: Connection prematurely closed BEFORE response; nested exception is reactor.netty.http.client.PrematureCloseException

传入的请求头如下:

{content-length=540, postman-token=ab567ea9-9025-413a-bd4b-87552a6c48b2, host=localhost:8080, content-type=application/json, connection=keep-alive, accept-encoding=gzip, deflate, br, user-agent=PostmanRuntime/7.29.0, accept=*/*}

请求排查异常原因并提供解决方案。


原因分析

  • Content-Length不匹配:手动传入的content-length=540和WebClient实际发送的请求体长度不一致,服务器校验失败后直接关闭连接,触发异常。WebClient会自动计算并设置正确的Content-Length或使用Chunked编码,无需手动指定。
  • 冗余请求头冲突:connection=keep-alive、host这类头属于HTTP底层连接管理字段,WebClient会自动处理,手动传入会干扰底层连接逻辑,导致连接提前关闭。

解决方案

方案1:过滤自动管理的请求头

修改头消费者,只保留业务相关头,跳过WebClient自动处理的字段:

Consumer<HttpHeaders> headersConsumer = headers -> {
    httpHeaders.forEach((key, value) -> {
        if (!key.equalsIgnoreCase(HttpHeaders.CONTENT_LENGTH)
            && !key.equalsIgnoreCase(HttpHeaders.CONNECTION)
            && !key.equalsIgnoreCase(HttpHeaders.HOST)) {
            headers.addAll(key, value);
        }
    });
};

方案2:只传递必要的自定义头

如果只有特定头需要传递,直接逐个指定,避免全量复制:

var responseMono = webClient
                  .post()
                  .uri(uri)
                  .header("postman-token", httpHeaders.getFirst("postman-token"))
                  .header("user-agent", httpHeaders.getFirst("user-agent"))
                  .header("accept-encoding", httpHeaders.getFirst("accept-encoding"))
                  .contentType(MediaType.APPLICATION_JSON)
                  .body(Mono.just(map), Map.class)
                  .exchangeToMono(response -> {
                     ref.set(response);
                     if (response.statusCode().equals(HttpStatus.OK)) {
                        return response.bodyToMono(String.class);
                     }
                     else {
                        return response.createException().flatMap(Mono::error);
                     }
             });

方案3:复制后移除冲突头

先复制所有头,再手动移除会引发冲突的字段:

var responseMono = webClient
                  .post()
                  .uri(uri)
                  .headers(headers -> {
                      headers.copyHeaders(httpHeaders);
                      headers.remove(HttpHeaders.CONTENT_LENGTH);
                      headers.remove(HttpHeaders.CONNECTION);
                      headers.remove(HttpHeaders.HOST);
                  })
                  .body(Mono.just(map), Map.class)
                  .exchangeToMono(response -> {
                     ref.set(response);
                     if (response.statusCode().equals(HttpStatus.OK)) {
                        return response.bodyToMono(String.class);
                     }
                     else {
                        return response.createException().flatMap(Mono::error);
                     }
             });

内容的提问来源于stack exchange,提问作者Kryptix

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.15 04:50:15