欢迎光临
我们一直在努力

InputStream输入流,传输数据不完整,org.apache.http.ConnectionClosedException: Premature end of Content-Length delimited message body

发送http请求给后端服务,在数据量大的时候报错:java

org.apache.http.ConnectionClosedException: Premature end of Content-Length delimited message body (expected: 144445481; received: 25370248)

意思是数据传输被提早终止了,指望传输144445481 B,只是传输了25370248 B。

http请求模型见上,在client用server的ip加端口访问服务,即便数据量大也没有问题。可是一旦经过域名访问,也就是经过Nginx访问,数据量大就会报上述错误。其实是Nginx对响应结果作了限制,若是Nginx超时时间设置的较短,而buffer很大的状况下,能够修改Nginx超时时间,将时间调大,这样在大数据量传输的过程当中就不会由于超时而终止。若是Nginx超时时间足够长,可是buffer较小的话,能够调大buffer来解决。

还有一点须要注意,就是同步异步的问题可能会引起这个问题,好比:后端

method A{异步

    语句1;大数据

    语句2(异步调用其余数据库查询);.net

    语句3(finally块关闭链接)server

}

在上面的逻辑中,若是方法A是同步调用,可是数据库查询是异步,可能的一种状况是:数据没有传输完成,可是语句3已经执行了,链接被关闭,也可能引起上面的问题。

网上查到的解决方案,设置http传输协议版本,改为1.0,这样消息体就会一次性全部传过来;

  HttpPost post = new HttpPost(builderUrl(url, requestParams));
  post.setProtocolVersion(HttpVersion.HTTP_1_0);

笔者问题。通过上述方法并未得到解决

原因

找到了上传文件InputStream不完整的原因,是因为网络传输文件的全部字节,可能会分几批进行发送。
InputStream的available()只是其中的一部分字节。

解决方法:

拿到全部的字节总数,再进行传输。可以使用apache的IOUtils来处理(由于网络极为糟糕的,这个方法也会出错。):

byte[] readBuffer = IOUtils.toByteArray(inStream);
inStream = new ByteArrayInputStream(readBuffer);

由于网络情况极为糟糕的情况下,上述方法也会出错,笔者又在两次请求之间添加了间隔时间,情况好像有所改善。另外也不一定非要使用IOUtils.toByteArray,传输不好,多数是网络状况导致的。

附贴上笔者的部分代码

        CloseableHttpResponse httpResponse = null;
        CloseableHttpClient httpClient = null;
        HttpEntity entity;

        // 这里自定义了一个线程随机等待时间的方法,随机等待50-90秒
        mySleep(50, 90);

        try {
            httpResponse = httpClient.execute(httpReq, localContext);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (httpResponse == null) {
                // 如果请求不到,进行重试。
                System.out.println("execute异常,重试....");
                // 线程等待
                mySleep(5, 7);
                try {
                    httpResponse = httpClient.execute(httpReq, localContext);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

        statusCode = httpResponse != null ? httpResponse.getStatusLine().getStatusCode() : 0;

        // 再试一次
        if (statusCode == 0) {
            System.out.println("execute异常,再次重试....");
            try {
                httpResponse = httpClient.execute(httpReq, localContext);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

读取数据

public static byte[] readInputStream(InputStream inStream) {
        ByteArrayOutputStream outStream = new ByteArrayOutputStream();
        // 创建一个Buffer字符串
        byte[] buffer = new byte[4096];
        // 每次读取的字符串长度,如果为-1,代表全部读取完毕
        try {
            int len = 0;

            // 使用一个输入流从buffer里把数据读取出来
            while ((len = inStream.read(buffer)) != -1) {
                // 用输出流往buffer里写入数据,中间参数代表从哪个位置开始读,len代表读取的长度
                // 每次把读取的内容,输出到目标路径文件中
                outStream.write(buffer, 0, len);             
            }
        } catch (IOException e) {
            System.out.println("写入出错,重试");
            readInputStream(inStream);
            e.printStackTrace();
        } finally {
            try {
                // 关闭输入流
                inStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        // 把outStream里的数据写入内存
        return outStream.toByteArray();
    }

使用(部分代码摘取):

                entity = httpResponse.getEntity();
                InputStream inputStream = entity.getContent();                
                if (inputStream != null) {
                    data = readInputStream(inputStream);
                }

                OutputStream outputStream = new FileOutputStream(sf.getPath() + "\\" + filename);
                outputStream.write(data);

上面代码进行了多次重试和多次等待。在网络极为糟糕的情况下有所改善。

赞(0)
版权归原作者所有,如有侵权请告知。达维营-前端网 » InputStream输入流,传输数据不完整,org.apache.http.ConnectionClosedException: Premature end of Content-Length delimited message body

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址