Feign调Post接口异常:Incomplete output stream

背景


最近使用了一个微服务权限管理框架,在使用feign调用其他服务的post接口时,总是调不通,报错如下

bash 复制代码
feign.RetryableException: 
    Incomplete output stream executing POST http://xxx

表示 Feign 在发送请求体(request body)时,输出流还没写完就被中断了

经过多方查找,发现是由于框架在实现RequestInterceptor 的配置类上,错误处理了Content-Length

分析


原先的配置类代码如下

java 复制代码
@Configuration
public class FeignConfig implements RequestInterceptor {
    @Override
    public void apply(RequestTemplate template) {
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        if (requestAttributes == null) {
            return;
        }

        HttpServletRequest request = ((ServletRequestAttributes) requestAttributes).getRequest();
        Enumeration<String> headerNames = request.getHeaderNames();
        if (headerNames != null) {
            while (headerNames.hasMoreElements()) {
                String name = headerNames.nextElement();
                Enumeration<String> values = request.getHeaders(name);
                while (values.hasMoreElements()) {
                    String value = values.nextElement();
                    template.header(name, value);
                }
            }
        }
    }
}

这段代码是一个 Feign 请求拦截器(RequestInterceptor 的实现,

主要用于在微服务间通过 Feign 进行 HTTP 调用时,自动透传 当前 HTTP 请求的请求头(Headers),确保关键信息(如认证 Token、追踪 ID 等)在服务调用链中不丢失。

其中,关键的代码在于

java 复制代码
Enumeration<String> values = request.getHeaders(name);
while (values.hasMoreElements()) {
    String value = values.nextElement();
    template.header(name, value);
}

作用是:取原始请求的所有 Header 字段名称,将原始请求的 Header 键值对注入到 Feign 请求模板,确保下游服务能接收到相同的头信息

但是,这里忽略了一个问题,将所有的 Header 字段都进行了注入,包括Content-Length

Content-Length 是 HTTP 报文头部(Header)中的一个标准字段,用来 指明请求体或响应体(body)的字节长度,单位是字节(byte)

场景 请求体类型 是否自动生成 说明
浏览器(fetch / axios JSON / 表单 ✅ 是 浏览器自动设置
Postman / curl 任意 ✅ 是 工具自动处理
Java RestTemplate JSON / 表单 ✅ 是 Spring 自动计算
Java HttpClient(JDK 11+) 字符串 / JSON ✅ 是 自动生成
Feign(常见调用) @RequestBody JSON ✅ 是 自动编码并设置
Feign 上传文件 MultipartFile ⚠️ 不一定 多数用 chunked,不设置 Content-Length
手写 HttpURLConnection 自定义 OutputStream ❌ 否 需要手动设置

我们的接口调用路径是这样的:

浏览器 -> 微服务A 接口1 -> feign 拦截器 -> 微服务B 接口2

结合上面的表格,在这个过程中,我们的Content-Length都应该是自动生成的

但是,我们在feign拦截器中,将微服务A 接口1Content-Length一并复制给了微服务B 接口2

Content-Length 是根据 HTTP 请求体或响应体的字节长度(byte) 计算出来的

而两者的请求体 字节长度不同,计算出来的Content-Length也不会相同

这样造成的结果便是:Content-Length不匹配问题,即太大或者太小

如果 Content-Length 数值设置错误,可能导致:

  • 数据截断(太小)
  • 请求挂起或超时(太大)

如图所示

最终微服务B 接口2得到了错误的Content-Length:10

实际上,它却发送了 100字节的数据,表现为表现为 写流中断Incomplete output stream

解决方法


既然知道了原因,那么修改也就简单了

我们可以在遍历Header字段时,不注入Content-Length,使其自动生成,即

java 复制代码
String name = headerNames.nextElement();
if (!"content-length".equals(name)) {
    Enumeration<String> values = request.getHeaders(name);
    while (values.hasMoreElements()) {
        String value = values.nextElement();
        template.header(name, value);
    }
}

这样,就避免了Content-Length不一致情况,修改之后,微服务接口接口也能成功调用了

参考资料


相关推荐
世界哪有真情几秒前
Trae 蓝屏问题
前端·后端·trae
一头生产的驴几秒前
java整合itext pdf实现固定模版pdf导出
java·python·pdf
魔都吴所谓2 分钟前
【python】快速实现pdf批量去除指定位置水印
java·python·pdf
Camel卡蒙3 分钟前
数据结构——字典树Trie(介绍、Java实现)
java·数据结构
Moment4 分钟前
NestJS 在 2025 年:对于后端开发者仍然值得吗 😕😕😕
前端·后端·github
kida_yuan4 分钟前
【Java】基于 Tabula 的 PDF 合并单元格内容提取
java·数据分析
Java水解10 分钟前
【Spring】Spring事务和事务传播机制
后端·spring
文心快码BaiduComate10 分钟前
文心快码实测Markdown排版工具开发
前端·后端·程序员
用户9047066835718 分钟前
java hutool 跟 JSONUtil 的关系
后端
渣哥18 分钟前
原文来自于:[https://zha-ge.cn/java/128](https://zha-ge.cn/java/128)
javascript·后端·面试