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
相关产品推荐
相关产品推荐

