前端文件上传(文件上传,分片上传,断点续传)

普通文件上传

思路:

首先获取用户选择的文件对象,并将其添加到一个 FormData 对象中。然后,使用 axios 的 post 方法将 FormData 对象发送到服务器。在 thencatch 中,我们分别处理上传成功和失败的情况,并输出相应的信息。

需要注意,在使用 axios 进行文件上传时,必须将数据格式设置为 multipart/form-data,否则文件对象将无法正确传输。

传统方式:

function handleFileSelect(e) {const formData = new FormData();formData.append("file", file);const header={"Content-Type": "multipart/form-data;charset=UTF-8"};axios.post("http://xxx.xxx.xx.x:xxxx/upload",formData,{headers: header,}).then((res) => {console.log(res);});
}

封装方法:

在大型项目中,我一般会把get,post,put,delete以及upload方法进行封装。

//封装upload方法
import axios from "axios";
const requests = axios.create({//配置对象baseURL: myBaseURL,timeout: 10000,
});
const header = {"Content-Type": "multipart/form-data;charset=UTF-8",
};
const http = {upload(url="",formData){return new Promise((resolve, reject) => {requests({url,data: formData,headers: header,method: "POST",}).then((res) => {resolve(res.data);return res;}).catch((err) => {reject(err);});});},
....
}
//封装请求方法
apiFun.upload = (formData) => {return http.upload("/user/headshot", formData);
};
//上传文件
function handleFileSelect(e) {const formData = new FormData();formData.append("file", file);ApiFun.upload(formData).then((res) => {console.log(res);ElMessage.success("上传成功");});}
}

分片上传

分片上传是将一个大文件切分成多个小块,然后将这些小块逐个上传到服务器的一种上传方式。

思路:

简单来说就是三个步骤:分片=》并行/串行发送分片=》合并请求

 为什么要做分片上传?通常大家第一会想到的就是因为文件太大了。

分片上传解决以下几个问题:

1. 大文件上传容易导致网络传输中断:当我们尝试上传一个大文件时,如果网络连接不稳定或上传过程中出现异常,整个文件都需要重新上传。而通过分片上传,即使某个小块上传失败,只需要重新上传该小块,而不必重新上传整个文件。

2. 降低服务器压力:如果直接上传一个大文件,服务器需要同时处理大量的数据,并且需要分配较大的内存空间来存储这些数据。而通过分片上传,可以将服务器的负载分散到多个小块的处理上,减轻了服务器的压力。

3. 提高上传速度和稳定性:将大文件切分成小块后,可以并行上传这些小块,从而提高上传速度。同时,如果某个小块上传失败,可以重试该小块,而不会影响其他小块的上传,从而提高上传的稳定性。

4. 支持断点续传:通过分片上传,服务器可以保存每个小块的上传状态,包括已上传的字节数和已确认的小块。如果上传过程中断,下次可以从上次中断的位置继续上传,实现断点续传的功能。

具体实现思路:

  • 将大文件转换成二进制流的格式
  • 利用流可以切割的属性,将二进制流切割成多份
  • 组装和分割块同等数量的请求块(或同等大小的请求块),并行或串行的形式发出请求
  • 待我们监听到所有请求都成功发出去以后,再给服务端发出一个合并的信号

 一般我会选择在文件小于5MB时普通文件上传,当文件大于5MB时进行分片上传。

整体逻辑就是:

将大文件进行分片

我这里封装了md5计算方法

'use strict';
import '../plugins/js-spark-md5.js'export default function (file, callback) {var blobSlice = File.prototype.slice || File.prototype.mozSlice || File.prototype.webkitSlice,file = file,chunkSize = 4194304,                             // Read in chunks of 4MB 即 4 * 1024 * 1024chunks = Math.ceil(file.size / chunkSize),currentChunk = 0,spark = new SparkMD5.ArrayBuffer(),              //向上取整,因为最后一块不一定满4MBfileReader = new FileReader();fileReader.onload = function (e) {console.log('read chunk nr', currentChunk + 1, 'of', chunks);spark.append(e.target.result);                   // Append array buffercurrentChunk++;if (currentChunk < chunks) {loadNext();} else {let data = {"etag": spark.end(),"chunks": chunks,"size": file.size,"blockToken": "",}callback(null, data);console.log('finished loading');}};fileReader.onerror = function () {callback('oops, something went wrong.');};function loadNext() {var start = currentChunk * chunkSize,end = ((start + chunkSize) >= file.size) ? file.size : start + chunkSize;fileReader.readAsArrayBuffer(blobSlice.call(file, start, end));}loadNext();
};

 因为我实现了多文件并行分片上传,所以这里在将文件加入列表时我就已经计算好了相关属性

当md5计算完毕,文件显示准备就绪。

创建切片请求:

返回结果的属性之一exist反应该文件是否上传过,如果存在,则可以实现秒传,无需再次上传。

如果不存在,则获取此次上传的目标ip和端口号

将每一个切片 并行/串行 的方式发出:

我这里使用promise实现了并行(如果是用循环遍历切片串行传输,可以通过循环下标i的值与切片总数相等来判断分片是否上传完毕)

且每个分片是大小一致的。

当所有分片上传完成后。再给服务器端发送合并请求。

文件合并请求:


断点续传

在分片上传的基础上,我们很容易考虑到断点续传的需求。

思路:

点击暂停按钮时停止上传。点击继续上传,继续上传剩下的分片或请求。

我们很容易想到给每个分片一个是否上传的状态标识来识别该分片是否上传完成。

法1:初始时所有分片的状态为未上传,当一个分片上传完成,将该标识设置为已上传。暂停上传时,将当前上传的分片也设置为未上传;重新进行上传时,就可以继续把其他未上传的分片上传了。

法2:将所有分片加入一个列表中,每当成功上传一个分片,就将该分片从列表中删除。而列表中剩下的分片就是还未上传的分片。


秒传

即前面分片上传中提到的。发送创建分片请求时,让服务器检查该文件是否上传过,如果是,则无需重复上传,直接显示上传成功实现秒传功能。


其他问题 之 上传过程中刷新页面怎么办

如果在上传过程中刷新了页面,通常会导致上传任务中断。

因为刷新页面会导致浏览器重新加载页面,之前的 JavaScript 代码和网络请求都会被取消。

当页面刷新后,可以尝试使用以下方法来处理上传任务的中断情况:

1. 利用浏览器的缓存机制:在上传之前,将文件对象保存到浏览器的本地存储或会话存储中。当页面刷新后,通过读取缓存中的文件对象信息,重新构建上传任务,并恢复之前的上传进度。

2. 检测页面刷新事件:可以通过监听 `beforeunload` 事件来捕获页面刷新的操作。在该事件触发时,可以弹出一个确认框,提示用户是否继续离开页面。如果用户选择离开页面,可以先中止当前的上传请求,然后再进行页面刷新。

该方法并不能完全保证上传任务的连续性和完整性。在实际应用中,为了确保上传任务的可靠性,通常建议在上传过程中避免刷新页面,或者提供其他手段来处理上传中断的情况,如支持断点续传功能。

使用 localStorage 实现断点续传的demo:

const input = document.getElementById('file-input');
const FILE_STORAGE_KEY = 'uploadedFile';// 读取本地存储的文件对象信息
const storedFile = localStorage.getItem(FILE_STORAGE_KEY);
let file = null;if (storedFile) {// 如果存在已上传的文件信息,则恢复上传任务file = JSON.parse(storedFile);
}input.addEventListener('change', function() {file = input.files[0];// 将文件对象保存到本地存储localStorage.setItem(FILE_STORAGE_KEY, JSON.stringify(file));startUpload();
});function startUpload() {if (!file) {console.log('请先选择文件');return;}const formData = new FormData();formData.append('file', file);axios.post('/upload', formData, {onUploadProgress: function(progressEvent) {// 处理上传进度变化if (progressEvent.lengthComputable) {const percentComplete = progressEvent.loaded / progressEvent.total * 100;console.log(percentComplete.toFixed(2) + '% 已上传');}}}).then(function(response) {// 处理上传完成事件console.log('上传完成');console.log(response.data);// 上传完成后,清除本地存储的文件信息localStorage.removeItem(FILE_STORAGE_KEY);}).catch(function(error) {// 处理上传错误事件console.error('上传出错');});
}// 监听页面刷新事件
window.addEventListener('beforeunload', function(event) {if (file) {// 中止当前的上传请求// ...// 移除本地存储的文件信息localStorage.removeItem(FILE_STORAGE_KEY);}
});

使用 localStorage 存储已选择的文件对象信息,并在页面刷新时恢复该信息。当用户重新选择文件时,更新文件对象并保存到 localStorage 中。在上传过程中,如果用户刷新页面,会触发 beforeunload 事件,我们可以在该事件中中止上传请求并移除 localStorage 中的文件信息。 


其他问题 之 某个切片上传失败怎么办

1. 重新上传该切片:如果上传失败的切片是由于网络等原因导致的,则可以尝试重新上传该切片。如果上传失败的切片数量较少,则可以通过手动重试的方式来完成。如果上传失败的切片数量较多,则可能需要设计一些自动化机制来处理重传逻辑,如使用队列等数据结构来记录上传失败的切片并进行重传。

2. 跳过该切片:如果上传失败的切片数量较多,或者由于某些原因无法进行重传,则可以考虑跳过该切片。具体实现方法可以根据上传任务的特点来确定,如将上传任务分为多个阶段,每个阶段上传一定数量的切片,如果某个阶段上传失败,则跳过该阶段并记录下失败的切片信息,待后续再进行重传。

3. 放弃上传任务:如果上传失败的切片数量较多,或者重传操作多次仍然无法恢复上传任务,则可以考虑放弃上传任务。在此情况下,可以将上传任务标记为“失败”状态,并记录下失败的切片信息。如果需要重新上传该文件,则可以在下一次上传任务中,首先检查之前已上传的切片信息,如果存在已上传的切片,则可以直接跳过这些切片并进行后续的上传操作。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/643724.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Java零基础学习19:集合

编写博客目的&#xff1a;本系列博客均根据B站黑马程序员系列视频学习和编写目的在于记录自己的学习点滴&#xff0c;方便后续回忆和查找相关知识点&#xff0c;不足之处恳请各位有缘的朋友指正。 一、集合和数组的对比 数组和集合很相似&#xff0c;但集合只能存储引用数据类…

Ask for Power Apps 消失了?

Ask for Power Apps 消失了? 背景替换定义一个接收数组的参数1.我们新建一个Text接收参数取名为**Arrlist**.定义一个参数类型是Array 背景 今天才发现&#xff0c;我在flow中想向power apps索要一个参数&#xff0c;但是之前的Ask for Power Apps 这个触发器怎么也找不到了。…

Aloha原理以及代码分析参考资料链接汇总

平台&#xff1a;CSDN Mobile Aloha 【软硬件原理代码解析】 作者&#xff1a;Yuezero_ Aloha 机械臂的学习记录3——AWE&#xff1a;Pycharm运行代码记录 作者&#xff1a;随机惯性粒子群 【EAI 007】Mobile ALOHA&#xff1a;一个低成本的收集人类示教数据的双臂移动操作硬…

2023 IoTDB Summit:中核武汉核电运行技术股份有限公司主管工程师方华建《IoTDB在核电数字化转型过程的应用实践》...

12 月 3 日&#xff0c;2023 IoTDB 用户大会在北京成功举行&#xff0c;收获强烈反响。本次峰会汇集了超 20 位大咖嘉宾带来工业互联网行业、技术、应用方向的精彩议题&#xff0c;多位学术泰斗、企业代表、开发者&#xff0c;深度分享了工业物联网时序数据库 IoTDB 的技术创新…

解决方案 | 基于SFTP协议的文件传输断点续传Java实现方案

背景 因项目需要&#xff0c;我们服务每天都需要通过SFTP协议来对接上下游进行文件传输&#xff0c;但是对于一些大文件&#xff0c;在与第三方公司的服务器对接过程中很可能会因为网络问题或上下游服务器性能问题导致文件上传或者下载被中断&#xff0c;每次重试都需要重新对…

LeetCode.2865. 美丽塔 I

题目 题目链接 分析 闲谈&#xff1a;每次读 LeetCode 的题目描述都要费老大劲&#xff0c;o(╥﹏╥)o 题意&#xff1a;这个其实意思就是以数组的每一位作为最高点&#xff0c;这个点&#xff08;数字&#xff09;左右两边的数字都不能大于这个数字(可以等于)&#xff0c;…

前端JavaScript篇之找出数组中重复的数字、js中数组是如何在内存中存储的?原生遍历数组的方式有哪些?请对以下数组,根据 `born` 的值降序排列

目录 找出数组中重复的数字方法一&#xff1a;使用 Set 数据结构方法二&#xff1a;排序数组 js中数组是如何在内存中存储的&#xff1f;原生遍历数组的方式有哪些&#xff1f;请对以下数组&#xff0c;根据 born 的值降序排列 找出数组中重复的数字 找出数组中的重复数字是一…

【赠书第18期】人工智能B2B落地实战:基于云和Python的商用解决方案

文章目录 前言 1 方案概述 2 方案实施 2.1 云平台选择 2.2 Python环境搭建 2.3 应用开发与部署 2.4 应用管理 2.5 安全性与隐私保护 3 方案优势与效益 4 推荐图书 5 粉丝福利 前言 随着云计算技术的快速发展&#xff0c;越来越多的企业开始将业务迁移至云端&#x…

云原生离线工作流编排利器 -- 分布式工作流 Argo 集群

作者&#xff1a;庄宇 在现代的软件开发和数据处理领域&#xff0c;批处理作业&#xff08;Batch&#xff09;扮演着重要的角色。它们通常用于数据处理&#xff0c;仿真计算&#xff0c;科学计算等领域&#xff0c;往往需要大规模的计算资源。随着云计算的兴起&#xff0c;阿里…

鸿蒙开发入门

下载和安装DevEco Studio&#xff1a; 文档中心https://developer.harmonyos.com/cn/docs/documentation/doc-guides-V3/software_install-0000001053582415-V3 配置鸿蒙开发环境&#xff1a; 文档中心https://developer.harmonyos.com/cn/docs/documentation/doc-guides-V3…

MySQL之数据库DDL

文章目录 MySQL数据库基本操作数据定义DDL对数据库的常用操作创建表修改表格式结构 MySQL数据库基本操作 首先我们先了解SQL的语言组成&#xff0c;他分为四个部分 数据定义语言&#xff08;DDL&#xff09;数据操纵语言&#xff08;DML&#xff09;数据控制语言&#xff08;…

亚马逊、eBay、TikTok等平台的综合运营实用工具分享!

亚马逊、eBay等电商平台为卖家提供了广阔的销售机会&#xff0c;但同时也带来了运营管理的挑战。为了提高运营效率和销售业绩&#xff0c;卖家需要借助一些实用工具。本文将介绍一些在亚马逊、eBay等平台上综合运营中非常有用的工具&#xff0c;帮助卖家更高效地管理店铺&#…

CC工具箱使用指南:【处理面要素空洞】

一、简介 面要素在经过一系列的处理后&#xff0c;可能会存在空洞。 有些小空洞面积过小&#xff0c;人工检查很容易遗漏&#xff0c;于是就做了这个工具。 目的就是获取面要素的空洞&#xff0c;或者去除空洞获取要素的边界。 二、工具参数介绍 右键点击面要素图层&#xf…

spring mvc 请求与响应

我是南城余&#xff01;阿里云开发者平台专家博士证书获得者&#xff01; 欢迎关注我的博客&#xff01;一同成长&#xff01; 一名从事运维开发的worker&#xff0c;记录分享学习。 专注于AI&#xff0c;运维开发&#xff0c;windows Linux 系统领域的分享&#xff01; 知…

神经网络的学习(Neural Networks: Learning)

1.代价函数 案例&#xff1a;假设神经网络的训练样本有&#x1d45a;个&#xff0c;每个包含一组输入&#x1d465;和一组输出信号&#x1d466;&#xff0c;&#x1d43f;表示神经网络层数&#xff0c;&#x1d446;&#x1d43c;表示每层的 neuron 个数(&#x1d446;&#…

k8s 容器 java 应用内存限制不生效

一 k8s java 应用内存限制不生效 回顾&#xff1a;Linux杂谈之java命令 namespace负责资源隔离 cgroups负责资源限制 容器JVM最佳实践 Metaspace 是 非 Heap 内存 管理空间,那么 Heap 就是操作空间 JVM内存模型简介 隔离&#xff1a; 两个进程完全隔离感知&#xff1…

VM虚拟机忘记密码,ISO镜像修改

VM虚拟机忘记密码&#xff0c;ISO镜像修改 制作镜像&#xff1a; 镜像已制作&#xff0c;可在文末链接自行获取从镜像启动系统 1&#xff09;添加IOS镜像文件&#xff1a; 2&#xff09;开机进去固件&#xff1a; 进入后选择对应的驱动器启动 3. 修改密码 点击修改密码软件&a…

【极数系列】Flink环境搭建(02)

【极数系列】Flink环境搭建&#xff08;02&#xff09; 引言 1.linux 直接在linux上使用jdk11flink1.18.0版本部署 2.docker 使用容器部署比较方便&#xff0c;一键启动停止&#xff0c;方便参数调整 3.windows 搭建Flink 1.18.0版本需要使用Cygwin或wsl工具模拟unix环境…

每日一题——LeetCode1309.解码字母到整数映射

方法一 个人方法&#xff1a; 由题意可得&#xff1a; 1、1-26对应a-z&#xff0c;只不过从10开始&#xff0c;后面要加#才能表示字母 2、10# - 26# 都是三位数&#xff0c;开头<2&#xff0c;结尾都为# 3、某个数后面两位如果不为#那么该数为1-9对应a-i&#xff0c;如果…

华为设备配置简单流分类

实验需求&#xff1a;10.1.1.0/24网段的PC访问PC3&#xff0c;流量进入AR1时&#xff0c;DSCP字段优先级为0&#xff0c;在AR1进行配置&#xff0c;将10.1.1.0/24网段流量的优先级映射为内部优先级46。 实验步骤&#xff1a; 步骤1&#xff1a;配置IP地址 [AR1]interface g0/…