下载链接被提前关闭
org.apache.http.ConnectionClosedException: Premature end of Content-Length delimited message body (expected: 100,273,812; received: 51,420,928)
异常信息
org.apache.http.ConnectionClosedException: Premature end of Content-Length delimited message body (expected: 100,273,812; received: 51,420,928)
at org.apache.http.impl.io.ContentLengthInputStream.read(ContentLengthInputStream.java:178)
at org.apache.http.conn.EofSensorInputStream.read(EofSensorInputStream.java:135)
at java.util.zip.CheckedInputStream.read(CheckedInputStream.java:82)
at java.io.FilterInputStream.read(FilterInputStream.java:133)
at com.aliyun.oss.event.ProgressInputStream.read(ProgressInputStream.java:118)
at java.util.zip.CheckedInputStream.read(CheckedInputStream.java:82)
at java.io.FilterInputStream.read(FilterInputStream.java:107)
原因之一:
从字面意思上看是预期是要接受100,273,812字节,但实际只接收了51,420,928字节,待下载的消息体提前结束了;真实原因有很多种,比如:
a.两次读取数据间隔时间超过设置的超时时间,浏览器会关闭一段时间没有发送或接收数据的连接;
b. httpclient请求超时设置得太短,而服务端处理的时间太长,eg: 服务器处理耗时需要5秒,而客户端请求超时只有3秒;
c. 下载的过程中出现了其他异常,服务端主动关闭了流。
解决方案1:
针对上面出现的三种情况一般解决方案:
- 在下载时提前告诉浏览器文件待下载的大小,在流write之前,设置header的Content-Length,让浏览器保持链接可用
response.setContentLengthLong(fileSize);
- 设置httpclient的请求超时时间比服务端处理时间稍微大点
clientConfiguration.setConnectionTimeout(connectionTimeout);
conf.setRequestTimeout(requestTimeout);
- 解决服务端出现的异常,文件流下载操作单独try-catch-finally
byte[] buffer = new byte[1024];
response.reset();
response.setContentType("application/octet-stream");
response.setCharacterEncoding(StandardCharsets.UTF_8.name());
String fileName = HttpUtils.encodeAttachmentName(businessFileDO.getFileName(), request) ;
response.addHeader("Content-Disposition", "attachment; filename=" + fileName);
response.setHeader("Accept-ranges", "bytes");
// 放在流write之前
//response.setHeader("Content-Length", String.valueOf(fileSize));
response.setContentLengthLong(fileSize);
try{
outputStream = response.getOutputStream();
while ((length = inputStream.read(buffer)) != -1) {
outputStream.write(buffer, 0, length);
}
outputStream.flush();
}finlly{
IOUtils.closeQuietly(outputStream);
IOUtils.closeQuietly(inputStream);
}