Spring Boot 3.3.2升级至3.3.3后MockWebServer测试报错问题排查
问题现象
将项目从Spring Boot 3.3.2升级至3.3.3后,使用okhttp3 MockWebServer的测试在特定场景下失败,报错信息如下:
WARN 10447 --- [mockwebserversandbox] [or-http-epoll-2] r.netty.http.client.HttpClientConnect : [1c6d7513-2, L:/127.0.0.1:45548 - R:127.0.0.1/127.0.0.1:59000] The connection observed an error java.lang.IllegalArgumentException: invalid version format: VERSION=9HTTP/1.1 at io.netty.handler.codec.http.HttpVersion.<init>(HttpVersion.java:135) ~[netty-codec-http-4.1.112.Final.jar:4.1.112.Final] at io.netty.handler.codec.http.HttpVersion.valueOf(HttpVersion.java:89) ~[netty-codec-http-4.1.112.Final.jar:4.1.112.Final] at io.netty.handler.codec.http.HttpResponseDecoder.createMessage(HttpResponseDecoder.java:195) ~[netty-codec-http-4.1.112.Final.jar:4.1.112.Final]
触发条件
当MockWebServer的Dispatcher返回以下响应时会触发问题:
return new MockResponse().setResponseCode(204).setBody("version=9");
此时下一个请求的HTTP版本属性会被前置字符串VERSION=9,变为VERSION=9HTTP/1.1而非正常的HTTP/1.1。
已尝试的操作
- 回退至Spring Boot 3.3.2可解决问题,但期望能正常升级至新版本
- 移除
setBody("version=9")可修复3.3.3中的问题,但不清楚具体原因 - 查阅HTTP状态码204的文档,其兼容性说明提到:服务器可能会在头部后错误地包含数据
问题根源分析
1. HTTP 204规范要求
根据HTTP标准,204 No Content响应绝对不能包含响应体。服务器返回204时,必须确保在响应头结束后没有任何额外的body数据。
2. 版本升级带来的严格处理
Spring Boot 3.3.3升级了相关依赖(如okhttp或netty的版本),这些依赖对不符合HTTP规范的响应处理变得更严格。在3.3.2中,旧版本的依赖可能会忽略204响应中多余的body数据,或者正确清理了连接缓冲区;而3.3.3中的新版本依赖没有兼容这种违规情况,导致多余的version=9数据残留在HTTP连接的缓冲区中。
3. 连接复用导致的解析错误
由于HTTP连接是复用的,下一个请求的响应解析器会读取缓冲区中残留的version=9,并将其与新响应的HTTP/1.1版本字符串拼接,最终形成非法的VERSION=9HTTP/1.1,触发Netty的版本格式校验异常。
结论
这个问题的核心是MockResponse的写法违反了HTTP 204的规范——给204响应设置了body内容。Spring Boot 3.3.3升级后的依赖更严格地遵循HTTP标准,没有兼容这种违规写法,从而暴露了问题。并非Spring Boot或其依赖存在Bug,而是之前的版本对违规情况做了兼容处理,新版本收紧了规范校验。
内容的提问来源于stack exchange,提问作者Codinio

