前端大文件上传和下载(分片上传)

一、问题

  • 日常业务中难免出现前端需要向后端传输大型文件的情况,这时单次的请求不能满足传输大文件的需求,就需要用到分片上传
  • 业务需求为:用户可以上传小于20G的镜像文件,并进显示当前上传进度
  • 前端:vue3.x+Element Plus组件+axios

二、解决

  • 解决思路简单为前端选择文件后读取到文件的基本信息,包括:文件的大小、文件格式等信息,用于前端校验,校验完成后将文件进行切片并通过请求轮询把切片传递给后端
  • Vue的元素代码如下,主要借助el-upload组件:
<template>...<!-- 文件上传 --><el-upload:show-file-list="false"actionclass="mirror-upload":http-request="putinMirror"><button>上传环境镜像</button></el-upload>...<!-- 进度显示 --><el-progress:percentage="progress":indeterminate="true"/>...
</template>
<script setup>// 引入封装好的接口api,根据提供的接口文档自行封装即可import {// 普通get请求apicheckMirrorFileApi,// 普通post请求apiuploadShardFileApi,} from "@/assets/api/uploadApi.js"import { ref } from 'vue'// 文件输进度条const progress = ref(0)...
</script>

1.第一步选择文件

  • 配合组件选取需要上传的文件
/* 上传环境镜像 分片上传 */
const putinMirror = async (file) => {// 校验文件是否符合规范(注意这里的异步方法,因为调用了接口加上await,校验函数若不调用接口可以不写await,否则返回promise对象)if (await checkMirrorFile(file)) {// 文件相关信息let files = file.file// 从0开始的切片let shardIndex = 0// 调用切片方法uploadFile(files, shardIndex)}
}

2.校验文件是否符合规范

  • 这一步可以根据需求来进行校验,这里需要通过接口校验当前服务器可用的磁盘容量来判断是否有足够的空间用于存放将要上传的文件
/* 校验上传镜像文件是否符合规范 */
const checkMirrorFile = async (file) => {// 校验文件格式是否正确,支持.acow2/.iso/.ovf/.zip/.tarlet fileType = file.file.name.split('.')if (fileType[fileType.length - 1] !== 'acow2' && fileType[fileType.length - 1] !== 'iso' && fileType[fileType.length - 1] !== 'ovf' && fileType[fileType.length - 1] !== 'zip' && fileType[fileType.length - 1] !== 'tar') {ElMessage.warning('文件格式错误,仅支持.acow2/.iso/.ovf/.zip/.tar')return false}// 校验文件大小是否满足let fileSize = file.file.size//文件大小是否超出20Gif (fileSize > 20 * 1024 * 1024 * 1024) {ElMessage.warning('上传文件大小不超过20G')return false}const res = await checkMirrorFileApi()if (res.code !== 200) {ElMessage.warning('暂时无法查看磁盘可用空间,请重试')return false}// 查看磁盘容量大小if (res.data.diskDevInfos && res.data.diskDevInfos.length > 0) {let saveSize = 0res.data.diskDevInfos.forEach(i => {// 磁盘空间赋值if (i.devName === '/dev/mapper/centos-root') {// 返回值为GB,转为字节BsaveSize = i.free * 1024 * 1024 * 1024}})// 上传的文件大小没有超出磁盘可用空间if (fileSize < saveSize) {return true} else {ElMessage.warning('文件大小超出磁盘可用空间容量')return false}} else {ElMessage.warning('文件大小超出磁盘可用空间容量')return false}
}

3.文件切片上传

  • 校验完成后就可以进行文件的切片上传了,这里用的类似接口轮询的方式,每次携带一个切片信息给后端,后端接受到切片并返回成功状态码后再进行下一次切片的上传,代码如下:
  • 当然这里后端没有过多的做切片的处理,可以通过前端使用多线程,或者不等接口响应成功就进行下一次传递切片的过程进行上传的提速,这里具体怎么实现看业务需求或者怎么配合上传
/* 文件切片上传 */
const uploadFile = async (file, shardIndex, createTime, savePath, relativePath, timeMillis) => {// 文件名let name = file.name// 文件大小let size = file.size// 分片大小let shardSize = 1024 * 1024 * 5// 分片总数let shardTotal = Math.ceil(size / shardSize)if (shardIndex >= shardTotal) {isAlive.value = falseprogress.value = 100return}// 文件开始结束的位置let start = shardIndex * shardSizelet end = Math.min(start + shardSize, size)// 开始切割let packet = file.slice(start, end)let formData = new FormData()formData.append("file", packet)formData.append("fileName", name)formData.append("size", size)formData.append("shardIndex", shardIndex)formData.append("shardSize", shardSize)formData.append("shardTotal", shardTotal)// 下面这些值是后端组装切片时需要的,跟前端关系不大if (createTime) formData.append("createTime", createTime)if (savePath) formData.append("savePath", savePath)if (shardIndex < shardTotal) {// 进度条保留两位小数展示progress.value = ((shardIndex / shardTotal) * 100).toFixed(2) * 1const res = await uploadShardFileApi(formData)if (res.code !== 200) {ElMessage.error(res.msg)progress.value = 0return}if (res.msg == '上传成功' && res.data.fileName && res.data.filePath) {// 这里为所有切片上传成功后进行的操作...}shardIndex++uploadFile(file, shardIndex, res.data.createTime, res.data.savePath, res.data.relativePath, res.data.timeMillis)}
}
  • 最后将1、2、3中的代码合起来就是完整的分片上传了(前端带有文件校验)

4.分片上传注意点

  • 首先就是需要配置一下Nginx,我这里的每一个切片文件的大小为5MB,但是上传第一片的时候会报413的状态码,因为Nginx默认上传文件的大小是1M,所以叫运维或者后端同学改一下配置参数,保证文件传输时不会受到服务器的限制

5.大文件下载

  • 这里简单说一下业务中遇到的大文件下载,上述镜像文件上传之后是支持用户下载的,所以怎样处理20G文件的下载也是需要考虑的,我与后端小伙伴尝试过通过range推流的方式来处理大文件的下载,当下载时除了控制台能看到后一直在推流过来,界面上不会出现下载进度的窗口,而且当文件大小超过2G会出现浏览器缓存不足导致推流的中断,这里没有系统研究具体原因
  • 解决方法是后端直接将文件所存的地址返回给我,当然也可以通过Nginx配置访问到文件存储的位置也可以,前端则通过创建a标签的方式进行下载,这样可以直接调用到浏览器自带的下载直接显示出来当前文件下载的相关信息:下载进度、传输的速率和文件大小,用户体验更好,代码如下:
const downloadMirror = async (item) => {let t = {id: item.id,}const res = await downloadMirrorApi(t)if (res.headers["content-disposition"]) {let temp = res.headers["content-disposition"].split(";")[1].split("filename=")[1]let fileName = decodeURIComponent(temp)// 通过创建a标签实现文件下载let link = document.createElement('a')link.download = fileNamelink.style.display = 'none'link.href = res.data.msgdocument.body.appendChild(link)link.click()document.body.removeChild(link)} else {ElMessage({message: '该文件不存在',type: 'warning',})}
}

最后问题就解决了,希望可以帮到你,如果有更好的方法欢迎补充讨论

前端大文件上传和下载(分片上传)相关推荐

  1. Akka实战:HTTP大文件断点上传、下载,秒传

    2019独角兽企业重金招聘Python工程师标准>>> 访问:https://github.com/yangbajing/scala-applications/tree/master ...

  2. 前端大文件上传及切片上传-提升上传效率

    一.使用场景: 1.大文件上传 2.网络环境环境不好,存在需要重传风险的场景 二.名词解释: 切片上传:也叫分片上传,就是将所要上传的文件,按照一定的大小,将整个文件分隔成多个数据块来进行分别上传,上 ...

  3. [转载]ASP.NET Core文件上传与下载(多种上传方式)

    ASP.NET Core文件上传与下载(多种上传方式) 前言 前段时间项目上线,实在太忙,最近终于开始可以研究研究ASP.NET Core了. 打算写个系列,但是还没想好目录,今天先来一篇,后面在整理 ...

  4. HTML转Canvas工具 前端生成图片工具 屏幕快照 html2canvas 下载 或上传至服务器 使用方法

    HTML转Canvas工具 前端生成图片工具 屏幕快照 html2canvas 下载 或上传至服务器 使用方法 <!-- 如果需要显示照片--><!-- <img :src=& ...

  5. 前端大文件上传解决方案

    本人在2010年时使用swfupload为核心进行文件的批量上传的解决方案.见文章:WEB版一次选择多个文件进行批量上传(swfupload)的解决方案. 本人在2013年时使用plupload为核心 ...

  6. 前端大文件上传断点续传解决方案

    之前仿造uploadify写了一个HTML5版的文件上传插件,没看过的朋友可以点此先看一下~得到了不少朋友的好评,我自己也用在了项目中,不论是用户头像上传,还是各种媒体文件的上传,以及各种个性的业务需 ...

  7. gitee最多上传多大文件_H5移动端图片压缩上传,基于Jquery的前端,实现拍照上传,选择相册

    下载文件 首先前往 https://gitee.com/cp.net/html5-make-upload-thumb 下载所需文件.注:如果你安装git,那么可以直接在你本地 git clone ht ...

  8. ASP.NET Core文件上传与下载(多种上传方式)

    前言 前段时间项目上线,实在太忙,最近终于开始可以研究研究ASP.NET Core了. 打算写个系列,但是还没想好目录,今天先来一篇,后面在整理吧. ASP.NET Core 2.0 发展到现在,已经 ...

  9. c#如何上传大文件到服务器,asp.net(C#)中上传大文件的几中常见应用方法

    asp.net(C#)中上传大文件的几中常见应用方法 更新时间:2008年11月25日 10:05:46   作者: 最近博客需要做一个文件上下载功能,我从网上找了点资料,整理了下希望对大家有帮助! ...

最新文章

  1. mysql备份与还原
  2. 目标检测中准确率accuracy的计算(precision是精度、查准率)(Recall是召回率、查全率)
  3. Mybatis用#{}从传递过来的参数中取值
  4. Numpy——常用的排序函数
  5. struts 进不了action方法
  6. 对JS中变量的浅微认识
  7. python入门安装
  8. 机器学习相关博客收藏(KL 散度、信息熵、谱聚类、EM、Isolation Kernel、iForest、元学习、小样本学习、课程学习)
  9. 百度文库无需VIP和下载券直接下载
  10. CAD学习笔记中级课【参数化】
  11. Docker 构建统一的前端开发环境
  12. matlab方程求解的实验,实验七用matlab求解常微分方程
  13. 五千字!详细解读链家「难而正确的事」
  14. python实现词云且更换背景图片
  15. 2022年抗癌行业研究报告
  16. kuka机器人焊接编程入门教程_焊接机器人操作编程与应用教学.pptx
  17. Python小记~索引字典
  18. Python基础教程:一次性搞定 Django Form
  19. 大学生关于激励自己的名言座右铭(合集)
  20. Android Studio与夜神模拟器链接

热门文章

  1. python中globals()_Python中globals()的原因?
  2. 1176:谁考了第k名
  3. DP1040国产替代TJA1040 TJA1044 5V供电,±40V接口耐压,1Mbps 高速CAN总线收发器
  4. 关系的完整性-实体完整性
  5. Ubuntu 使用play命令播放音乐 mp3 wav 等文件
  6. 智能扑克牌识别软件(Python+YOLOv5深度学习模型+清新界面)
  7. EDIUS替换素材时如何保证原有特效不变
  8. 170916_算法导论学习(四)_2.3 设计算法_练习
  9. 火车购票系统服务器端uml活动图,火车购票系统uml类图-时序图-状态图-协作图-活动图-对象图--用例图.doc...
  10. 链表逆序的三大方法(Python实现)