这个错误 “too many bytes written executing POST” 通常发生在使用 java.net.HttpURLConnection
时,当你设置了固定的内容长度(Content-Length
),但实际写入到输出流的字节数超过了这个预设的长度。
Spring Cloud OpenFeign 在使用 HttpURLConnection
作为底层客户端时(通过 feign.Client.Default
),它会尝试计算请求体的大小,并设置 Content-Length
头部,然后调用 HttpURLConnection.setFixedLengthStreamingMode(int contentLength)
。如果后续写入的数据超过了这个 contentLength
,就会抛出这个 IOException
。
以下是可能的原因和排查、解决步骤:
-
Content-Length
计算不准确:- 自定义 Encoder 问题: 如果你使用了自定义的
feign.codec.Encoder
,需要确保你的encode
方法正确地计算了序列化后对象的大小,并将其反映在返回的RequestTemplate
的body()
中,或者确保写入的数据量与 OpenFeign 自动计算的Content-Length
一致。 - 数据在序列化后发送前被修改: 某种罕见情况下,如果在
Content-Length
已经根据序列化对象计算得出后,请求体数据又被无意中增加了,可能导致此问题。
- 自定义 Encoder 问题: 如果你使用了自定义的
-
请求体内容问题:
- 字符编码: 确保客户端和服务器端对请求体的字符编码(如 UTF-8)有统一的理解。如果
String
转换为byte[]
时使用的编码与计算Content-Length
时不一致,可能导致字节数不匹配。默认情况下,OpenFeign 的String
类型请求体会使用 UTF-8。 - 特殊字符或二进制数据: 如果你发送的是复杂的对象或包含特殊字符、二进制数据,确保你的 Encoder 能够正确处理并计算其字节长度。
- 字符编码: 确保客户端和服务器端对请求体的字符编码(如 UTF-8)有统一的理解。如果
-
HttpURLConnection
的 Bug 或特性:HttpURLConnection
相比 Apache HttpClient 或 OkHttp 来说,功能较少,也更容易出现一些边界情况的问题。
排查和解决步骤:
-
启用 Feign 的详细日志:
在你的application.yml
或application.properties
中为你的 Feign 客户端开启FULL
日志级别,这样可以看到请求头(包括Content-Length
)和请求体。logging: level: # 替换成你的 Feign 客户端接口所在的包名 com.example.yourpackage.YourFeignClient: DEBUG # 或者 TRACE feign: client: config: # default 应用于所有 Feign 客户端,也可以针对特定客户端配置 default: loggerLevel: FULL
观察日志中发送的
Content-Length
值和实际请求体的大小是否匹配。你可以手动计算一下请求体的字节数,看是否与Content-Length
一致。 -
检查你的
Encoder
:- 如果你使用的是默认的 Encoder (如
JacksonEncoder
),通常它在计算 JSON 大小时是准确的。 - 如果你使用了自定义的
Encoder
,请仔细检查其逻辑,特别是计算和写入字节流的部分。
- 如果你使用的是默认的 Encoder (如
-
简化请求:
尝试发送一个非常简单的请求体(比如一个简单的 JSON 对象),看是否还会出现问题。如果简单请求正常,那么问题可能出在复杂请求体的数据或序列化上。 -
尝试切换 HTTP 客户端:
HttpURLConnection
是 OpenFeign 的默认选项之一,但通常不推荐用于生产环境,特别是对于复杂场景或需要更多控制的场景。考虑切换到更健壮的 HTTP 客户端,如 Apache HttpClient 或 OkHttp。
添加依赖:- OkHttp:
<dependency>
- OkHttp: