不知道为什么至少我找到的文章里面都没说过这个问题。记录一下。有些http的服务器在相应Range请求时的处理会有问题,比如请求为Range: bytes=0-1023,但是有可能会在0-1000时就认为已经传完被断开连接,原因不明,在我的使用中都是以一定的概率出现这种情况。
解决方案,不指定 Range 的结束字节,完全由客户端自行控制读多少后主动停止
private void doDownloadChunk(String url, Path tempFile, long startByte, long endByte,
int threadId, AtomicLong downloadedBytes, long totalSize,
DownloadTask task, AtomicLong readNubmer) throws IOException {
Request request = new Request.Builder()
.url(url)
.addHeader("Range", "bytes=" + startByte + "-")//只写请求的起始,不写结束
.build();
long totalRead = 0;
try (Response response = client.newCall(request).execute()) {
if (!response.isSuccessful()) {
throw new IOException("请求失败: " + response.code());
}
ResponseBody body = response.body();
if (body == null) {
throw new IOException("响应体为空");
}
long l = (endByte - startByte) + 1;
// 使用FileChannel进行随机写入
try (RandomAccessFile raf = new RandomAccessFile(tempFile.toFile(), "rw");
BufferedInputStream inputStream = new BufferedInputStream(body.byteStream())) {
raf.seek(startByte);
int cache = 8192;
byte[] buffer = new byte[cache];
int bytesRead = 0;
while (true) {
//主要是这里需要计算还需要接收多少数据才能结束
if(l - totalRead < cache){
cache = (int) (l - totalRead);
if (cache == 0){
break;
}
buffer = new byte[cache];//这里我偷懒就直接创建新的对象了
}
bytesRead = inputStream.read(buffer);
if (bytesRead == -1) {
break; // 流结束
}
// 检查任务是否被取消
if (task.getStatus() == DownloadStatus.CANCELLED) {
break;
}
raf.write(buffer, 0, bytesRead);
totalRead += bytesRead;
// 更新总下载进度
downloadedBytes.addAndGet(bytesRead);
task.setDownloaded(downloadedBytes.get());
}
}
}catch (Exception e){
readNubmer.set(startByte + totalRead);
throw e;
}
}