http网络请求与下载进度

server/2024/9/19 19:43:33/ 标签: http, 网络协议, 网络
http://www.w3.org/2000/svg" style="display: none;">

Http_request 目录

一、XMLHttpRequest

在使用 Fetch API 进行网络请求时,原生的 Fetch API 并不直接支持获取下载进度的功能,因为 Fetch API 主要是基于 Promise 的,它主要关注于请求的成功或失败,以及响应数据的处理,而不直接处理像进度跟踪这样的底层细节。

不过,你可以通过一些技巧或方法间接实现下载进度的跟踪。以下是一些常用的方法:

1. 使用 XMLHttpRequest

虽然 Fetch API 较为现代,但如果你需要跟踪下载进度,XMLHttpRequest 可能是一个更好的选择。XMLHttpRequest 提供了 onprogress 事件,可以用来追踪下载进度。

var xhr = new XMLHttpRequest();
xhr.open('GET', 'your-file-url', true);
xhr.responseType = 'blob';xhr.onprogress = function (e) {if (e.lengthComputable) {var percentComplete = (e.loaded / e.total) * 100;console.log(percentComplete + '% downloaded');}
};xhr.onload = function () {if (this.status == 200) {// 处理响应数据}
};xhr.send();

在上述代码中,我们创建了一个 XMLHttpRequest 对象,并设置了 onprogress 事件处理函数。在该函数中,通过判断 e.lengthComputable 是否为真,来确定是否可以计算下载进度。如果可以计算,则通过 e.loaded 和 e.total 计算出已下载的百分比,并将其打印到控制台

2.XMLHttpRequest 的进一步封装

   xhrToDownload(options, onProgress, onSuccess, onError) {return new Promise((resolve, reject) => {const xhr = new XMLHttpRequest();xhr.open(options.method || 'GET', options.url);xhr.responseType = options.responseType || 'blob';xhr.onprogress = function(e) {if (e.lengthComputable) {const progress = (e.loaded / e.total) * 100;onProgress && onProgress(progress);}};xhr.onload = function(e) {if (xhr.status === 200) {// onSuccess && onSuccess(xhr.response);console.log('上传成功', xhr);resolve({ status: xhr.status, data: xhr.response })} else {onError && onError(xhr.statusText);reject({ status: xhr.status, data: xhr.statusText }); // 拒绝 Promise}}xhr.onerror = function(e) {onError && onError(xhr.statusText);reject({ status: xhr.status, data: xhr.statusText }); // 拒绝 Promise};xhr.send();});},

这个示例进一步封装了 XMLHttpRequest,使其可以返回一个 Promise,方便进行异步处理。

3. 创建 a 标签下载

        downloadFile(blob, fileName = '2.mp4') {// 创建a 标签const a = document.createElement('a');const blobUrl = URL.createObjectURL(blob);a.setAttribute('href', blobUrl);a.setAttribute('download', fileName);a.style.display = 'none';document.body.appendChild(a);a.click();document.body.removeChild(a);URL.revokeObjectURL(blobUrl)},

使用实例:

    async downloadVideo(row) {const url = row.path;if (!url) {return;}var index = this.tableData.findIndex(item => item.id === row.id);// 使用示例const response = await this.xhrToDownload({ url: url }, (progress) => {console.log('Download progress:', progress);if (index !== -1) {this.tableData[index].downLoadProgress = progress}}, (res) => {// 这里处理 Blob,例如保存到 IndexedDB、FileSystem API 或其他console.log('Download successful:', res);// 如果你确实需要下载文件,可以在这里创建 <a> 标签并触发点击}, (error) => {console.error('Download failed:', error);})if (response && response.status === 200) {this.downloadFile(response.data)}},

二、 Fetch API

1. 使用 Fetch API

  • 链式调用

            fetch(url).then(res => {return res.blob()}).then(res => {console.log('res', res);})
    
  • async - await 语法糖

        // const response = await fetch(url)// const blod = await response.blob()

2. 使用 Stream API 和 ReadableStream

Fetch API 支持响应体作为 ReadableStream,但直接使用它来跟踪进度可能不太直观。不过,你可以通过监听流的读取操作来大致估计进度(虽然这通常不如 XMLHttpRequest 那样精确)。

    //your_file_url fetch('http://127.0.0.1:456/proxy/DJI_0003.MP4')fetch('http://127.0.0.1:456/proxy/DJI_0003.MP4').then(response=>{console.log(response);const reader = response.body.getReader() //  ReadableStreamconst contentLength = response.headers.get('content-length')let readTotal = 0if(!contentLength){console.log('无法获取进度');return}const sizeTotal = parseInt(contentLength)const chunks =[]function read(){reader.read().then(({done,value})=>{if(done){console.log('下载完成');const type = response.headers.get('content-type')const blob = new Blob(chunks,{type})return}readTotal += value.lengthconst progress = Math.ceil(readTotal/sizeTotal*100)console.log('下载进度:',progress);chunks.push(value)read()})}read()})

注意:上面的代码示例并不直接计算下载进度,因为 ReadableStream API 并不直接提供总大小信息(除非你在响应头中通过 Content-Length 获取)。你需要有一个方式来获取文件的总大小,以便能够计算进度。

3. 使用fetch下载并获取进度

简单获取下载进度fetchToDownlod(url, options, onProgress, onSuccess, onError) {try {// eslint-disable-next-line no-async-promise-executorreturn new Promise(async(resolve, reject) => {const response = await fetch(url, options);const reader = response.body.getReader();// Step 2:获得总长度(length)const contentLength = +response.headers.get('Content-Length');console.log('contentLength', contentLength);// Step 3:读取数据let receivedLength = 0; // 当前接收到了这么多字节const chunks = []; // 接收到的二进制块的数组(包括 body)// eslint-disable-next-line no-constant-conditionwhile (true) {const { done, value } = await reader.read();if (done) {// 如果没有更多的数据可读,则退出循环break;}chunks.push(value);receivedLength += value.length;const progress = Math.round(receivedLength / contentLength * 100);onProgress && onProgress(progress);}// 将响应体转换为 Blob 对象const blob = new Blob(chunks, { type: 'application/octet-stream' });if (response.status === 200) {resolve({ status: response.status, blob });}if (response.status === 404) {reject({ status: response.status, blob });}});} catch (err) {console.log('err', err);return Promise.reject(err);}},

调用实例:

       async downloadVideo(row) {const url = row.path;if (!url) {return;}let fileName = 'text.mp4'const lastIndex = url.lastIndexOf('/');if (lastIndex !== -1) {fileName = url.substring(lastIndex + 1);}var index = this.tableData.findIndex(item => item.id === row.id);const options = {method: 'GET', // *GET, POST, PUT, DELETE, etc.mode: 'cors', // no-cors, *cors, same-origincache: 'no-cache', // *default, no-cache, reload, force-cache, only-if-cachedcredentials: 'same-origin', // include, *same-origin, omitresponseType: 'blob', //重要代码'Access-Control-Allow-Origin': '*','Access-Control-Allow-Credentials': true,headers: {'Content-Type': 'application/json'}}const res = await this.fetchToDownlod(url, options, (progress) => {// console.log('Download progress:', progress);if (index !== -1) {this.tableData[index].downLoadProgress = progress}})console.log('res', res);if (!res || res.status !== 200) {return this.$message.error('下载失败')}this.downloadFile(res.blob, fileName)},

结论

如果你的应用需要精确地跟踪下载进度,并且你的环境允许,使用 XMLHttpRequest 可能是最直接和简单的方法。如果你正在寻找更现代的方法,并可以接受一些复杂性,你可以考虑使用 Service Workers 或 Stream API 来实现类似的功能。


http://www.ppmy.cn/server/117670.html

相关文章

xml中SQL执行错误(使用另外一张表的两个字段,组装SQL的where查询条件)

SQL实现功能描述&#xff1a;根据系统设置中的商店到期提醒周期、单位&#xff0c;在过期提醒的列表中&#xff0c;对数据进行周期展示 错误复现&#xff1a; Mapper接口中抽象方法的定义如下&#xff1a; Page<ShopVo> queryList(Param(“vo”) ShopVo shopVo ,Page&…

四个pdf软件分享,你更爱哪一款?

如果说现在用的最多的电子文档是什么&#xff0c;不是Word就是PDF&#xff0c;所以PDF编辑器几乎成了我们日常工作中不可或缺的工具。但面对市面上琳琅满目的PDF编辑器&#xff0c;到底哪一款才是你的菜呢&#xff1f;今天&#xff0c;我就来和大家聊聊我用过的四款编辑器&…

部署Prometheus+Grafana批量监控Linux服务器

在 Linux 服务器上使用 Docker 容器快速部署 Prometheus 和 Grafana 监控系统&#xff0c;同时通过 node_exporter 采集全面的系统性能数据。整个流程涵盖了从环境配置到搭建一个全面监控平台的每个步骤。 一键安装Node Exporter Node Exporter 是 Prometheus 生态系统中的一个…

Nacos与Eureka的区别:深入解析微服务中的服务注册与发现

在微服务架构中&#xff0c;服务注册与发现是确保各个服务之间高效通信与协调的重要机制。随着云原生应用的快速发展&#xff0c;服务治理的需求也在不断增长。在这一背景下&#xff0c;Nacos和Eureka作为两种主流的服务注册与发现工具&#xff0c;各具特色和优势。本文将深入分…

除了字符串前导的*号之外,将串中其它*号全部删除

要求 假定输入的字符串中只包含字母和*号。请编写函数fun&#xff0c;它的功能是:除了字符串前导的*号之外&#xff0c;将串中其它*号全部删除。在编写函数时&#xff0c;不得使用C语言提供的字符串函数。函数fun中给出的语句仅供参考。 例如&#xff0c;字符串中的内容为:-**…

GBase 8s数据类型与java.sql.Types对应关系

GBase 8s数据类型与java.sql.Types对应关系 GBase 8s类型类型java.sql.Typesjava类型名称SMALLINT5SMALLINTINTEGER4INTEGERBIGINT-5BIGINTINT8-5BIGINTSMALLFLOAT7REALFLOAT8DOUBLEDECIMAL3DECIMALMONEY3DECIMALCHAR1CHARNCHAR1CHARVARCHAR12VARCHARNVARCHAR12VARCHARVARCHAR…

基于Vue.js的超市商品管理导购中心设计与实现(任务书)

本科毕业论文&#xff08;设计&#xff09;任务书 学院&#xff1a;数学与数据科学学院 学生姓名 专业班级 信息与计算科学202班 学号 校内指导教师姓名 职称/职务 副教授 签名 校外指导教师姓名 职称/职务 工程师 签名 论文题目 基于Vue.js的超市商品管理导购中心 起始日期…

Web安全与网络安全:SQL漏洞注入

Web安全与网络安全&#xff1a;SQL漏洞注入 引言 在Web安全领域&#xff0c;SQL注入漏洞&#xff08;SQL Injection Vulnerability&#xff09;是一种极具破坏性的安全威胁。它允许攻击者通过向Web应用程序的输入字段中插入或“注入”恶意的SQL代码片段&#xff0c;从而操纵后…

uni-app 应用名称 跟随系统语言 改变

官方已确认BUG:&#xff1a;https://ask.dcloud.net.cn/question/164804 { "name" : "%app.name%",//这里随便写&#xff0c;配置了 locales,name 就不生效了 "appid" : "", "description" : "", "versi…

Pytorch详解-Pytorch核心模块

Pytorch核心模块 一、Pytorch模块结构_pycache__Cincludelibautogradnnoptimutils 二、Lib\site-packages\torchvisiondatasetsmodelsopstransforms 三、核心数据结构——Tensor&#xff08;张量&#xff09;在深度学习中&#xff0c;时间序列数据为什么是三维张量&#xff1f;…

基于鸿蒙API10的RTSP播放器(七:亮度调节功能测试)

目标&#xff1a; 当我的手指在设备左方进行上下移动的时候&#xff0c;可以进行屏幕亮度的调节&#xff0c;在调节的同时&#xff0c;有实时的调节进度条显示 步骤&#xff1a; 界面逻辑&#xff1a;使用Stack() 组件&#xff0c;完成音量图标和进度条的组合显示&#xff0c…

Kubernetes Pod镜像的3种状态

Kubernetes Pod镜像的3种状态 1. Pending状态2. Running状态3. Unknown状态💖The Begin💖点点关注,收藏不迷路💖 1. Pending状态 定义:Pod已被创建但尚未启动。 原因: 资源不足(CPU、内存等)。调度策略或标签选择器不匹配。镜像正在从仓库下载中。解决方案:检查资…

java 网络编程URL与URLConnection的使用

Java中的网络编程不仅限于Socket编程&#xff0c;还包括使用java.net.URL和java.net.URLConnection来进行简单的网络请求和数据获取。URL类用于表示统一资源定位符&#xff08;Uniform Resource Locator&#xff09;&#xff0c;而URLConnection类提供了与URL进行通信的功能。下…

RedisTemplate操作ZSet的API

文章目录 ⛄概述⛄常见命令有⛄RedisTemplate API❄️❄️ 向集合中插入元素&#xff0c;并设置分数❄️❄️向集合中插入多个元素,并设置分数❄️❄️按照排名先后(从小到大)打印指定区间内的元素, -1为打印全部❄️❄️获得指定元素的分数❄️❄️返回集合内的成员个数❄️❄…

【无人机设计与控制】四旋翼飞行无人机姿态控制ADRC非线性自抗扰控制Simulink仿真

摘要 本研究针对四旋翼飞行无人机姿态控制&#xff0c;提出了一种基于非线性自抗扰控制&#xff08;ADRC&#xff09;的控制策略。通过Simulink对系统进行了建模和仿真&#xff0c;验证了所设计控制器在不同工况下的有效性和鲁棒性。仿真结果表明&#xff0c;所设计的控制器能…

TensorFlow 笔记

------------------------------- 1. 创建模型阶段 ------------------------------- 1. Activation 激活函数&#xff0c; 属于模型的一个层&#xff0c;可以用于中间层&#xff0c;输出层。 ReLU (Rectified Linear Unit), 修正线性单元&#xff0c;即 max(0, x)&#xff…

【目标检测数据集】锯子数据集1107张VOC+YOLO格式

数据集格式&#xff1a;Pascal VOC格式YOLO格式(不包含分割路径的txt文件&#xff0c;仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数)&#xff1a;1107 标注数量(xml文件个数)&#xff1a;1107 标注数量(txt文件个数)&#xff1a;1107 标注…

创建一个Java项目在IntelliJ IDEA中

创建一个Java项目在IntelliJ IDEA中是一个直观且功能强大的过程&#xff0c;适合从初学者到经验丰富的开发者。IntelliJ IDEA由JetBrains开发&#xff0c;被誉为Java开发领域最受欢迎的IDE&#xff08;集成开发环境&#xff09;之一&#xff0c;它提供了代码自动补全、版本控制…

模仿抖音用户ID加密ID的算法MB4E,提高自己平台ID安全性

先看抖音的格式 对ID加密的格式 MB4EENgLILJPeQKhJht-rjcc6y0ECMk_RGTceg6JBAA 需求是 同一个ID 比如 413884936367560 每次获取得到的加密ID都是不同的&#xff0c;最终解密的ID都是413884936367560 注意这是一个加密后可解密原文的方式&#xff0c;不是单向加密 那么如下进行…

2024/9/15 408“回头看”之应用层小总结(下)

域名系统DNS: 本地域名服务器 本地域名服务器起着代理的作用&#xff0c;会将报文转发到根域名服务器、顶级域名服务器、权限域名服务器。 递归查询&#xff1a; 迭代查询&#xff1a; 文件传送协议FTP: FTP客户和FTP服务器之间使用的是tcp连接。 控制连接使用21端口&…