WireMock测试中Java HTTP Client发POST请求遇RST_STREAM异常
WireMock + Java HttpClient POST请求抛出RST_STREAM异常:排查思路与解决方案
问题现象
使用WireMock开展测试时,通过Java HttpClient的HttpRequest.BodyPublishers.ofInputStream()发送POST请求会抛出以下异常:
java.io.IOException: Received RST_STREAM: Stream cancelled at java.net.http/jdk.internal.net.http.HttpClientImpl.send(HttpClientImpl.java:586) at java.net.http/jdk.internal.net.http.HttpClientFacade.send(HttpClientFacade.java:123) ...(省略剩余栈信息)
但以下场景测试可正常运行:
- 强制HttpClient使用HTTP/1.1
- 替换为
HttpRequest.BodyPublishers.ofString()构建请求体 - 改用GET请求
请求dump显示,使用ofInputStream()时请求包含HTTP/2升级头及chunked编码内容:
POST /foo HTTP/1.1 Connection: Upgrade, HTTP2-Settings Host: localhost:2727 HTTP2-Settings: AAEAAEAAAAIAAAABAAMAAABkAAQBAAAAAAUAAEAA Transfer-encoding: chunked Upgrade: h2c User-Agent: Java-http-client/17.0.6 5 stuff 0
使用ofString()时,上述升级头与chunked编码会消失;强制HTTP/1.1时升级头仍存在,但请求可正常处理。
排查思路
- HTTP版本兼容性验证:异常仅在默认HTTP/2模式下触发,强制HTTP/1.1即可恢复正常,说明问题出在WireMock与Java HttpClient的HTTP/2交互逻辑中。
- 请求编码差异分析:
ofInputStream()默认采用chunked编码,而ofString()会自动设置Content-Length头,避免chunked编码。结合请求dump推测,WireMock对HTTP/2下的chunked编码请求处理存在缺陷。 - WireMock版本缺陷排查:当前使用的WireMock 3.3.1可能存在未修复的HTTP/2相关bug,需确认新版本是否解决该问题。
解决方案
方案1:强制使用HTTP/1.1
在构建HttpRequest时显式指定HTTP版本,绕过HTTP/2的兼容性问题:
HttpRequest httpRequest = HttpRequest.newBuilder() .uri(URI.create("http://localhost:" + PORT + "/foo")) .version(HttpClient.Version.HTTP_1_1) // 强制使用HTTP/1.1 .POST(HttpRequest.BodyPublishers.ofInputStream(() -> new ByteArrayInputStream("stuff".getBytes(StandardCharsets.UTF_8)))) .build();
方案2:手动设置Content-Length头
为ofInputStream()请求添加Content-Length头,避免chunked编码,让HTTP/2交互正常进行:
byte[] bodyContent = "stuff".getBytes(StandardCharsets.UTF_8); HttpRequest httpRequest = HttpRequest.newBuilder() .uri(URI.create("http://localhost:" + PORT + "/foo")) .header("Content-Length", String.valueOf(bodyContent.length)) .POST(HttpRequest.BodyPublishers.ofInputStream(() -> new ByteArrayInputStream(bodyContent))) .build();
方案3:升级WireMock版本
WireMock后续版本可能修复了HTTP/2兼容性问题,将依赖升级至最新稳定版(如3.5.0+):
<dependency> <groupId>org.wiremock</groupId> <artifactId>wiremock</artifactId> <version>3.5.0</version> <scope>test</scope> </dependency>
原因说明
Java 11+的HttpClient默认优先使用HTTP/2,当使用ofInputStream()且未指定Content-Length时,会采用chunked编码并发起h2c(明文HTTP/2)升级请求。而WireMock 3.3.1的底层服务器在处理这种带chunked编码的h2c升级请求时,无法正确解析请求体,因此主动发送RST_STREAM帧关闭连接。ofString()因自动设置Content-Length避免了chunked编码,强制HTTP/1.1则绕过了HTTP/2处理逻辑,因此均能正常工作。
内容的提问来源于stack exchange,提问作者Mark Schäfer
相关产品推荐
相关产品推荐

