Feign客户端异常IOException: Incomplete output stream解决方案

一. 前言

在开发SpringCloud项目架构的项目时,服务与服务之间的调用通过Feign客户端实现,在做一个从Feign客户端到service服务端的POST请求时,Feign客户端为服务消费者觉得,service服务端为服务提供者角色,提供者角色中service服务端Controller类中方法测试正常,但却在Feign客户端返回时报错,大致异常如下:

Caused by: java.io.IOException: Incomplete output stream
    at sun.net.www.protocol.http.HttpURLConnection.getInputStream0(HttpURLConnection.java:1523)
    at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1492)
    at java.net.HttpURLConnection.getResponseCode(HttpURLConnection.java:480)
    at feign.Client$Default.convertResponse(Client.java:152)
    at feign.Client$Default.execute(Client.java:74)
    .........................................

二. 分析异常

关键异常: IOException: Incomplete output stream, 从表面意思看,是IO异常,异常信息也是从Feign客户端源码报出来的,这样一步一步锁定异常范围,根据异常调用链得知最终异常出现的地方是:sun.net.www.protocol.http.HttpURLConnection.getInputStream0(HttpURLConnection.java:1523)
HttpURLConnection.getInputStream0方法1523行。经过搜索资料,原来feign采用jdk原生HttpURLConnection向下游服务发起http请求(源码详见feign.Client.Default),先到getInputStream0方法看看:

 private synchronized InputStream getInputStream0() throws IOException {
        if(!this.doInput) {
            throw new ProtocolException("Cannot read from URLConnection if doInput=false (call setDoInput(true))");
        } else if(this.rememberedException != null) {
            if(this.rememberedException instanceof RuntimeException) {
                throw new RuntimeException(this.rememberedException);
            } else {
                throw this.getChainedException((IOException)this.rememberedException);
            }
        } else if(this.inputStream != null) {
            return this.inputStream;
        } else {
            if(this.streaming()) {
                if(this.strOutputStream == null) {
                    this.getOutputStream();
                }

                this.strOutputStream.close();
                if(!this.strOutputStream.writtenOK()) {   
                    throw new IOException("Incomplete output stream"); // 1523行
                }
            }..........

        // this.strOutputStream.writtenOK()方法
        boolean writtenOK() {
            return this.closed && !this.error;
        }

看起来,this.error是true导致的,也就是说在OutputStream写入流时出错。

三. 解决方案

1. 加feign-httpclient依赖

没办法,只能用Apache HttpClient替换掉原生HttpURLConnection。加入依赖:

<!-- 使用Apache HttpClient替换Feign原生httpclient -->
<!-- feign-httpclient内含Apache HttpClient -->
        <dependency>
            <groupId>com.netflix.feign</groupId>
            <artifactId>feign-httpclient</artifactId>
            <version>8.17.0</version>
        </dependency>

2. 开启Feign支持httpclient

然后在application.yml中添加如下:

feign:
  httpclient:
    enabled: true

再次重新调用,一切恢复正常。

3. 补充

引入Apache HttpClient包时,需要注意指定Content-Type,不然会产生以下异常:

Caused by: java.lang.IllegalArgumentException: MIME type may not contain reserved characters

解决办法 :

@RequestMapping(value = "/getUser", method = RequestMethod.GET, consumes = MediaType.APPLICATION_JSON_VALUE) 

注解中指定: Content-Type 即 指定 consumes 的属性值

4. 其他异常情况

如果你又遇到了下面这个异常,可参考我对网友提出的问题回复的帖子,按照对应的依赖版本匹配上即可解决问题:openfeign里面配置httpclient出错。

异常日志如下:

Caused by: java.lang.NoSuchMethodError: feign.Response.create(ILjava/lang/String;Ljava/util/Map;Lfeign/Response$Body;)Lfeign/Response;

Caused by: java.lang.NoSuchMethodError: feign.Response.create(ILjava/lang/String;Ljava/util/Map;Lfeign/Response$Body;)Lfeign/Response;

网友的提问点醒了我:
在这里插入图片描述
然后我的解决方式:

在这里插入图片描述

四. 参考

参考: https://www.jianshu.com/p/6397e2cd1fae

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Thinkingcao

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值