当前位置: 首页 > news >正文

OKHTTP断点续传

OKHTTP断点续传

文章目录

  • OKHTTP断点续传
    • HTTP断点续传知识点
      • Range
      • Content Range
      • Etag&If-Range(文件唯一标志)
    • OKHTTP断点下载
    • OKHTTP 简单短断点下载代码示例

Android 断点续传一直是面试的高频问点,这里从HTTP断点续传知识和Android续传思路结合一起,总结出关于Android断点续传做法。

HTTP断点续传知识点

HTTP1.1 协议中默认支持获取文件的部分内容,主要是通过头部两个参数:Range和Content Range 来实现的,客户端发送请求是对应是Range ,服务器响应时是对应Content-Range。

Range

是客户端想要获取文件的部分内容的关键字段,Range 参数中指定获取内容的起始字节的位置和终止字节的位置。他的一般格式为:

<font style="color:rgb(51, 51, 51);background-color:rgb(248, 248, 248);">Range:(unit=first byte </font>**<font style="color:rgb(51, 51, 51);">pos</font>**<font style="color:rgb(51, 51, 51);background-color:rgb(248, 248, 248);">)-[</font>**<font style="color:rgb(51, 51, 51);">last</font>**<font style="color:rgb(51, 51, 51);background-color:rgb(248, 248, 248);"> byte </font>**<font style="color:rgb(51, 51, 51);">pos</font>**<font style="color:rgb(51, 51, 51);background-color:rgb(248, 248, 248);">]</font>

例如:

Range: bytes=0-499      表示第 0-499 字节范围的内容 、
Range: bytes=-500       表示最后 500 字节的内容 
Range: bytes=500-       表示从第 500 字节开始到文件结束部分的内容 
Range: bytes=0-0,-1     表示第一个和最后一个字节 
Range: bytes=500-600,601-999 同时指定几个范围

Content Range

在接受到客户端的Range请求后,服务器会在响应的头部添加Content 参数,返回可以接受的文件字节范围和文件的总大小,他们格式如下:

<font style="color:rgb(51, 51, 51);background-color:rgb(248, 248, 248);">Content-Range: bytes (unit first byte </font>**<font style="color:rgb(51, 51, 51);">pos</font>**<font style="color:rgb(51, 51, 51);background-color:rgb(248, 248, 248);">) - [</font>**<font style="color:rgb(51, 51, 51);">last</font>**<font style="color:rgb(51, 51, 51);background-color:rgb(248, 248, 248);"> byte </font>**<font style="color:rgb(51, 51, 51);">pos</font>**<font style="color:rgb(51, 51, 51);background-color:rgb(248, 248, 248);">]/[entity legth]</font>

例如:

<font style="color:navy;">Content-Range</font><font style="color:rgb(51, 51, 51);background-color:rgb(248, 248, 248);">: bytes </font><font style="color:teal;">0</font><font style="color:rgb(51, 51, 51);background-color:rgb(248, 248, 248);">-</font><font style="color:teal;">499</font><font style="color:rgb(51, 51, 51);background-color:rgb(248, 248, 248);">/</font><font style="color:teal;">22400</font>_<font style="color:rgb(153, 153, 136);">// 0-499 是指当前发送的数据的范围,而 22400 则是文件的总大小。</font>_

不使用文件断点续传响应体内容:<font style="color:rgb(51, 51, 51);background-color:rgb(248, 248, 248);">HTTP/</font><font style="color:teal;">1.1200Ok</font>

使用文件断点续传响应体的内容:<font style="color:rgb(51, 51, 51);background-color:rgb(248, 248, 248);">HTTP/</font><font style="color:teal;">1.1206</font><font style="color:rgb(51, 51, 51);background-color:rgb(248, 248, 248);"> Partial </font><font style="color:navy;">Content</font>

服务器文件发生变化,会导致续传的请求是肯定是失败的,为了处理这种服务器文件资源发生改变的问题,在RFC2616中定义了Last-Modified和Etag来判断文件资源是否发生改变。

Etag&If-Range(文件唯一标志)

  • Etag:作为文件唯一的标志,这个标志可以是文件的hash值或者是一个版本
  • If-Range:用于判断实体是否发生改变,如果未改变,服务器发送客户端丢失的部分,否则发送整个实体,一般格式为:If-Range: Etag | HTTP-Date If-Range可以使用Etag或者Last-Modified返回的值,当没有ETag却有Last-Modified时,可以把Last-Modified作为If-Range的值
  • 验证过程:
    • step1:客户端发起续传请求,头部包含Range和If-Range参数
    • step2:服务器中收到客户端的请求之后,将客户端与服务器的Etag进行对比
      • 相等:请求文件资源没有发生变化,应答报文是206
      • 不相等:请求文件资源发生变化,应答报文为200

OKHTTP断点下载

  • step 1:判断检查本地是否有下载文件,若存在,则获取已下载的文件大小 downloadLength,若不存在,那么本地已下载文件的长度为 0
  • step 2:获取将要下载的文件总大小(HTTP 响应头部的 content-Length)
  • step 3:比对已下载文件大小和将要下载的文件总大小(contentLength),判断要下载的长度
  • step 4:再即将发起下载请求的 HTTP 头部中添加即将下载的文件大小范围(Range: bytes = downloadLength - contentLength)

OKHTTP 简单短断点下载代码示例


/*** String 在执行AsyncTask时需要传入的参数,可用于在后台任务中使用。* Integer 后台任务执行时,如果需要在界面上显示当前的进度,则使用这里指定的泛型作为进度单位。* Integer 当任务执行完毕后,如果需要对结果进行返回,则使用这里指定的泛型作为返回值类型。*/
public class DownloadTask extends AsyncTask<String, Integer, Integer> {public static final int TYPE_SUCCESS = 0;public static final int TYPE_FAILED = 1;public static final int TYPE_PAUSED = 2;public static final int TYPE_CANCELED = 3;private DownloadListener listener;private boolean isCanceled = false;private boolean isPaused = false;private int lastProgress;public DownloadTask(DownloadListener listener) {this.listener = listener;}/*** 这个方法中的所有代码都会在子线程中运行,我们应该在这里处理所有的耗时任务。** @param params* @return*/@Overrideprotected Integer doInBackground(String... params) {InputStream is = null;RandomAccessFile savedFile = null;File file = null;long downloadLength = 0;   //记录已经下载的文件长度//文件下载地址String downloadUrl = params[0];//下载文件的名称String fileName = downloadUrl.substring(downloadUrl.lastIndexOf("/"));//下载文件存放的目录String directory = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).getPath();//创建一个文件file = new File(directory + fileName);if (file.exists()) {//如果文件存在的话,得到文件的大小downloadLength = file.length();}//得到下载内容的大小long contentLength = getContentLength(downloadUrl);if (contentLength == 0) {return TYPE_FAILED;} else if (contentLength == downloadLength) {//已下载字节和文件总字节相等,说明已经下载完成了return TYPE_SUCCESS;}OkHttpClient client = new OkHttpClient();/*** HTTP请求是有一个Header的,里面有个Range属性是定义下载区域的,它接收的值是一个区间范围,* 比如:Range:bytes=0-10000。这样我们就可以按照一定的规则,将一个大文件拆分为若干很小的部分,* 然后分批次的下载,每个小块下载完成之后,再合并到文件中;这样即使下载中断了,重新下载时,* 也可以通过文件的字节长度来判断下载的起始点,然后重启断点续传的过程,直到最后完成下载过程。*/Request request = new Request.Builder().addHeader("RANGE", "bytes=" + downloadLength + "-" + contentLength)  //断点续传要用到的,指示下载的区间.url(downloadUrl).build();try {Response response = client.newCall(request).execute();if (response != null) {is = response.body().byteStream();savedFile = new RandomAccessFile(file, "rw");savedFile.seek(downloadLength);//跳过已经下载的字节byte[] b = new byte[1024];int total = 0;int len;while ((len = is.read(b)) != -1) {if (isCanceled) {return TYPE_CANCELED;} else if (isPaused) {return TYPE_PAUSED;} else {total += len;savedFile.write(b, 0, len);//计算已经下载的百分比int progress = (int) ((total + downloadLength) * 100 / contentLength);//注意:在doInBackground()中是不可以进行UI操作的,如果需要更新UI,比如说反馈当前任务的执行进度,//可以调用publishProgress()方法完成。publishProgress(progress);}}response.body().close();return TYPE_SUCCESS;}} catch (IOException e) {e.printStackTrace();} finally {try {if (is != null) {is.close();}if (savedFile != null) {savedFile.close();}if (isCanceled && file != null) {file.delete();}} catch (Exception e) {e.printStackTrace();}}return TYPE_FAILED;}/*** 当在后台任务中调用了publishProgress(Progress...)方法之后,onProgressUpdate()方法* 就会很快被调用,该方法中携带的参数就是在后台任务中传递过来的。在这个方法中可以对UI进行操作,利用参数中的数值就可以* 对界面进行相应的更新。** @param values*/@Overrideprotected void onProgressUpdate(Integer... values) {int progress = values[0];if (progress > lastProgress) {listener.onProgress(progress);lastProgress = progress;}}/*** 当后台任务执行完毕并通过Return语句进行返回时,这个方法就很快被调用。返回的数据会作为参数* 传递到此方法中,可以利用返回的数据来进行一些UI操作。** @param status*/@Overrideprotected void onPostExecute(Integer status) {switch (status) {case TYPE_SUCCESS:listener.onSuccess();break;case TYPE_FAILED:listener.onFailed();break;case TYPE_PAUSED:listener.onPaused();break;case TYPE_CANCELED:listener.onCanceled();break;default:break;}}public void pauseDownload() {isPaused = true;}public void cancelDownload() {isCanceled = true;}/*** 得到下载内容的完整大小** @param downloadUrl* @return*/private long getContentLength(String downloadUrl) {OkHttpClient client = new OkHttpClient();Request request = new Request.Builder().url(downloadUrl).build();try {Response response = client.newCall(request).execute();if (response != null && response.isSuccessful()) {long contentLength = response.body().contentLength();response.body().close();return contentLength;}} catch (IOException e) {e.printStackTrace();}return 0;}}

public class DownloadListener {/*** 通知当前的下载进度* @param progress*/void onProgress(int progress);/*** 通知下载成功*/void onSuccess();/*** 通知下载失败*/void onFailed();/*** 通知下载暂停*/void onPaused();/*** 通知下载取消事件*/void onCanceled();}

推荐阅读:Android OkHttp 文件上传与下载的进度监听扩展 - 掘金

相关文章:

OKHTTP断点续传

OKHTTP断点续传 文章目录 OKHTTP断点续传HTTP断点续传知识点RangeContent RangeEtag&If-Range&#xff08;文件唯一标志&#xff09; OKHTTP断点下载OKHTTP 简单短断点下载代码示例 Android 断点续传一直是面试的高频问点&#xff0c;这里从HTTP断点续传知识和Android续传思…...

软件测试学习笔记丨Flask操作数据库-ORM

本文转自测试人社区&#xff0c;原文链接&#xff1a;https://ceshiren.com/t/topic/23426 什么是持久化 是把数据保存到可永久保存的存储设备中&#xff08;比如磁盘&#xff09;。持久化的主要应用是将内存中的数据存储在关系型数据库中&#xff0c;当然也可以存储在磁盘文件…...

ABAP 开发的那些小技巧

在对话框程序中的选择屏幕添加图标 要在选择屏幕中添加图标&#xff0c;其中包括参数&#xff1a; 在参数的选择文本中或选择选项(select-option)中写入 01 或选择选项&#xff1a; 您可以使用 01、02、03&#xff0c;依此类推&#xff0c;以获取不同的不同图标。 在运行时…...

电科金仓(人大金仓)更新授权文件(致命错误: XX000: License file expired.)

问题:电科金仓(人大金仓)数据库链接异常,重启失败,查看日志如下: 致命错误: XX000: License file expired. 位置: PostmasterMain, postmaster.c:725 解决方法: 一、下载授权文件 根据安装版本在官网下载授权文件(电科金仓-成为世界卓越的数据库产品与服务提供商)…...

玩转「HF/魔搭/魔乐」平台

模型下载 Hugging Face 下载到 GitHub CodeSpace CodeSpace创建环境&#xff1a; # 安装transformers pip install transformers4.38 pip install sentencepiece0.1.99 pip install einops0.8.0 pip install protobuf5.27.2 pip install accelerate0.33.0下载internlm2_5-7b…...

鸿蒙系统的优势 开发 环境搭建 开发小示例

HarmonyOS是面向多智能终端、全场景的分布式操作系统,为消费者提供跨终端的无缝体验.华为开发者联盟从HarmonyOS应用设计、开发、测试、推广变现等环节全方位助力开发者。 开发者可以通过以下步骤学习鸿蒙系统的开发&#xff1a; 基础理论学习&#xff1a; 了解鸿蒙系统概述&a…...

python批量合并excel文件

当工作中发现有多个excel表需要进行相同的操作或者需要汇总在一起&#xff0c;一个一个处理太费时间&#xff0c;以下的python代码能够帮你解决这个问题~ import pandas as pd import os# 设置Excel文件所在的文件夹路径和合并文件的输出路径 folder_path D:\\Desktop\\dat…...

AWS S3 JavaScript SDK(v3)常用操作

安装 aws s3 sdk npm install aws-sdk/client-s3配置 创建 ~/.aws/credentials 文件&#xff0c;添加以下配置项&#xff1a; [default] aws_access_key_id<...> aws_secret_access_key<...> region<...>S3 SDK常用桶操作 获取桶列表 import {S3Client,…...

数据结构——图的基本操作

文章目录 1.图2.图的结构体定义3.图的初始化4.添加顶点、删除顶点4.1添加顶点4.2删除顶点 5.添加边、删除边5.1添加边5.2删除边 6.打印图7.main函数 在生命旅途中&#xff0c;我们就像是一个个节点&#xff0c;被无数看不见的边相连。每一次的相识与相离&#xff0c;都在这张巨…...

掌握全球速递:在表格中高效利用国际快递公式查询快递

在当今全球化的商业环境中&#xff0c;国际快递服务已成为连接世界各地企业与个人的重要桥梁。无论是跨国企业间的货物运输&#xff0c;还是个人用户的海外购物需求&#xff0c;国际快递都扮演着不可或缺的角色。然而如何快速准确地获取大量国际快递的物流轨迹成为了一个挑战。…...

【MySQL系列】字符集设置

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…...

Vue2进阶之Vue3高级用法

Vue3高级用法 响应式Vue2&#xff1a;Object.definePropertyObject.definePropertythis.$set设置响应式 Vue3&#xff1a;Proxy composition APIVue2 option API和Vue3 compositionAPIreactive和shallowReactivereadonly效果toRefs效果 生命周期main.jsindex.htmlLifeCycle.vue…...

基于微信的追星小程序+ssm(lw+演示+源码+运行)

摘 要 随着我国经济迅速发展&#xff0c;人们对手机的需求越来越大&#xff0c;各种手机软件也都在被广泛应用&#xff0c;但是对于手机进行数据信息管理&#xff0c;对于手机的各种软件也是备受用户的喜爱&#xff0c;追星小程序被用户普遍使用&#xff0c;为方便用户能够可以…...

【51单片机】串口通信原理 + 使用

学习使用的开发板&#xff1a;STC89C52RC/LE52RC 编程软件&#xff1a;Keil5 烧录软件&#xff1a;stc-isp 开发板实图&#xff1a; 文章目录 串口硬件电路UART串口相关寄存器 编码单片机通过串口发送数据电脑通过串口发送数据控制LED灯 串口 串口是一种应用十分广泛的通讯接…...

优选算法第五讲:位运算模块

优选算法第五讲&#xff1a;位运算模块 1.常见的位运算总结2.判断字符是否唯一3.丢失的数字4.两整数之和5.只出现一次的数字II6.消失的两个数字 1.常见的位运算总结 2.判断字符是否唯一 链接: link class Solution { public:bool isUnique(string astr) {if(astr.size() >…...

【07】Maven项目多环境打包配置

&#xff08;1&#xff09;Web项目使用Maven进行多模块划分开发之后&#xff0c;面临一个问题&#xff0c;即如何加载不同环境的配置文件打包发布到不同的环境中&#xff1f; &#xff08;2&#xff09;不同的环境有开发环境、测试环境、线上生产环境等。 &#xff08;3&#x…...

嵌入式Linux入门具备:C语言基础与基本驱动学习(2):Linux GIibc IO基础

标准IO 标准 I/O 虽然是对文件 I/O 进行了封装&#xff0c;但事实上并不仅仅只是如此&#xff0c;标准 I/O 会处理很多细节&#xff0c;譬如分配 stdio 缓冲区、以优化的块长度执行 I/O 等&#xff0c;这些处理使用户不必担心如何选择使用正确的块长度。I/O 库函数是构建于文件…...

【微服务】Docker 容器化

一、初识Docker 1. 为什么需要 Docker 大型项目组件较多&#xff0c;运行环境也较为复杂&#xff0c;部署时会遇到一些问题&#xff1a; 依赖关系复杂&#xff0c;容易出现兼容性的问题开发、测试、生产环境有差异 Docker 如何解决依赖的兼容问题 将应用的Libs&#xff08;…...

[前端] 为网站侧边栏添加搜索引擎模块

前言 最近想给我的个人网站侧边栏添加一个搜索引擎模块&#xff0c;可以引导用户帮助本站SEO优化&#xff08;让用户可以通过点击搜索按钮完成一次对本人网站的搜索&#xff0c;从而实现对网站的搜索引擎优化&#xff09;。 最开始&#xff0c;我只是想实现一个简单的百度搜索…...

解决CORS (跨源资源共享) 错误

问题引入 前端代码 <template><div id"hello-vue" class"demo">{{ message }}</div><el-button type"primary" click"handleClick">我是一个按钮</el-button></template><script setup>//加…...

Kettle的优势

Kettle说具有非常强大的数据处理功能&#xff0c;没有做不到只有你想不到或者你还没有学会使用&#xff0c;如果确实做不到的情况下你还可以开发插件来进行数据处理&#xff0c;其中Kettle也提供了广泛的数据处理和转换功能&#xff0c;包括数据抽取、清洗、转换、合并、过滤等…...

如何快速掌握文档扫描优化:ScanTailor完整指南

如何快速掌握文档扫描优化&#xff1a;ScanTailor完整指南 【免费下载链接】scantailor 项目地址: https://gitcode.com/gh_mirrors/sc/scantailor 你是否曾为扫描文档的歪斜、污渍和模糊而烦恼&#xff1f;ScanTailor就是你的救星&#xff01;这款强大的开源工具能智能…...

AI生成论文的查重率区间是多少?目前控制AIGC疑似率最好用的软件有哪些?

毕业、投稿阶段难题频发&#xff0c;常规 AI 撰写论文&#xff0c;查重率普遍处在 35%-60% 区间&#xff0c;AIGC 疑似率更是达到 50%-70%&#xff0c;知网、维普检测极易不合格&#xff0c;进而引发答辩延后、错失评优资格等问题。下文实测四款热门工具&#xff0c;帮大家找准…...

CANN-Ascend-C存储体系-昇腾NPU的四级缓存怎么用才算对

写 Ascend C 算子&#xff0c;最常犯的错误不是计算写错&#xff0c;是数据搬运写错。昇腾NPU有四级存储&#xff0c;每一级的容量、带宽、延迟都不同。数据该放在哪一级、什么时候搬、搬多少&#xff0c;直接决定算子性能。 四级存储级别名称容量带宽延迟用途L0HBM&#xff08…...

GD32/STM32串口高效收数秘籍:巧用IDLE中断判断一帧数据收完

GD32/STM32串口高效收数实战&#xff1a;IDLE中断DMA的黄金组合 在嵌入式开发中&#xff0c;串口通信就像设备间的"普通话"&#xff0c;但如何高效接收不定长数据帧却让不少工程师头疼。想象一下无人机飞控与地面站的通信场景&#xff1a;数据包可能短至几个字节的指…...

嵌入式条码扫描头:从核心原理到八大行业应用实战

1. 项目概述&#xff1a;从“扫码”到“感知”的嵌入式革命每次在超市收银台听到“嘀”的一声&#xff0c;或者在快递驿站看到工作人员拿着手持设备快速扫过包裹&#xff0c;我们都在与条码扫描技术打交道。但你是否想过&#xff0c;这些看似简单的“扫码”动作背后&#xff0c…...

实测taotoken在不同时段api调用的响应延迟与稳定性表现

&#x1f680; 告别海外账号与网络限制&#xff01;稳定直连全球优质大模型&#xff0c;限时半价接入中。 &#x1f449; 点击领取海量免费额度 实测taotoken在不同时段api调用的响应延迟与稳定性表现 对于依赖大模型API进行开发的团队而言&#xff0c;服务的响应延迟与稳定性…...

DeepSeek LeetCode 2561. 重排水果 Java实现

LeetCode 2561. 重排水果题目分析有两个长度为 n 的数组 basket1 和 basket2&#xff0c;每个数组包含若干水果。每次操作可以交换两个数组中的任意水果&#xff0c;花费为这两个水果中较小的那个值。目标是使两个数组中的水果种类和数量完全相同&#xff08;即两个数组重排后相…...

【飞机】基于matlab数据驱动的多传感器飞机健康监测系统【含Matlab源码 15551期】

&#x1f4a5;&#x1f4a5;&#x1f4a5;&#x1f4a5;&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;&#x1f49e;&#x1f49e;&#x1f49e;&#x1f49e;&#x1f49e;&#x1f49e;欢迎来到海神之光博客之家&#x1f49e;&#x1f49e;&#x1f49e;&#x1f49…...

okbiye 毕业论文功能深度解析:从开题到终稿的高校规范级写作辅助方案

okbiye-免费查重复率aigc检测/开题报告/毕业论文/智能排版/文献综述/AI PPT毕业论文 - Okbiye智能写作https://www.okbiye.com/ai/bylw 引言 毕业论文写作是高校学生学业生涯的关键环节&#xff0c;也是不少人面临的一大挑战。从确定选题、搭建框架&#xff0c;到撰写正文、格…...