首页 > 其他分享 >大文件切片上传+断点续传解决方案-前后端实现

大文件切片上传+断点续传解决方案-前后端实现

时间:2023-09-24 11:44:19浏览次数:33  
标签:uploaded 断点续传 const 文件 切片 let file 上传

上传文件大家应该都做过,前端直接把file文件传给后端就ok了,但是大文件这样传就会造成页面假死,体验极差。如果遇到网络不稳定的时候,中途上传失败的话,又要从头开始传,本来文件就大,还慢。所以今天我们用一种新方法-切片上传+断点续传

前端实现:
页面上很简单,我就放了进度条和一个上传文件组件,你可以按照三方ui来进行替换

<div class="box">
<progress value="0"></progress>
<br />
<input type="file" text="选择文件"/>
</div>

主要看逻辑实现

1、获取页面元素,初始化变量(vue中获取元素使用ref即可)

let ipt = doc.querySelector("input");
let progress = doc.querySelector("progress");
const chunkSize = 64 * 1024; //切片大小
let uploaded = 0; //已上传多少

2、 input绑定change事件(如果有专门的上传按钮,就给按钮绑定点击事件,如下图2)

思路:

通过read函数,把blob文件转为字符串,然后打成MD5
然后设置进度条的max为文件的size
判断缓存中是否有上传的进度,有就把切片初始值设置缓存中的值
设置循环,当前上传的大小 < 文件size时,进行切片,使用file.slice(起始值,起始值 + 切片大小)
把当前切片append进formdata,然后传给后端
然后把修改切片起始值,设置缓存进度,设置进度条当前值

// blob转为为字符串
const read = (file) => {
let reader = new FileReader();
return new Promise((resolve, reject) => {
reader.onload = function (event) {
const arrayBuffer = event.target.result;
resolve(arrayBuffer);
};
reader.onerror = reject;
reader.readAsBinaryString(file);
});
};

ipt.addEventListener("change", async (event) => {
let file = event.target.files[0];
if (!file) {
return;
}
ipt.value = null;
let content = await read(file);
let hash = md5(content);//转成hash,保证文件唯一
let { size, name, type } = file;
const local = localStorage.getItem(uploaded);//断点重传标志
progress.max = size;
if (local) {
uploaded = Number(local);
}
while (uploaded < size) {
//切片大小
const chunk = file.slice(uploaded, uploaded + chunkSize, type);
let fd = new FormData();
fd.append("name", name);
fd.append("size", size);
fd.append("type", type);
fd.append("file", chunk);
fd.append("offset", uploaded);
fd.append("hash", hash);
try {
await axios.post("http://localhost:5454/upload", fd);
} catch (error) {
console.log("上传失败");
}

uploaded += chunkSize;
localStorage.setItem(uploaded, uploaded);//设置传递进度
progress.value = uploaded;
}
console.log("上传成功");
});

btn.addEventListener('click',async()=>{
let file = ipt.files[0]
})

后端实现:
思路:

利用express-fileupload插件后,file在req.files中取,其他数据在req.body取
设置文件名,利用extreme获取传来的文件的后缀名,拼接在跟目录的upload文件夹下
判断offset != 0,就是已上传但是本地没有文件,创建文件并写入,否则写入到已经存在的文件中

//app.js
const express = require("express");
const bodyParser = require("body-parser");
const fileUpload = require("express-fileupload");
const { resolve, extname } = require("path");
const { existsSync, appendFileSync, writeFileSync } = require("fs");

const app = express();
const PORT = "5454";

// 跨域
app.all("*", (req, res, next) => {
res.header("Access-Control-Allow-origin", "*");
res.header("Access-Control-Allow-Methods", "POST,GET");
next();
});

app.use(bodyParser.json());
app.use(fileUpload());
app.use('/',express.static('upload'))

// app.get("/", (req, res) => {
// res.send("Hello World!");
// });

app.post("/upload", (req, res) => {
const { name, size, type, offset, hash } = req.body;
const { file } = req.files;
// console.log(name, size, type, offset, hash);
//取后缀
let ext = extname(name);
let fileName = resolve(__dirname, "./upload/" + hash + ext);
if (offset != 0) {
if (!existsSync(fileName)) {
res.status(400).send({
msg:'文件不存在'
})
return
}
appendFileSync(fileName,file.data)
res.send({
code:200,
data:'http://localhost:5454/' + fileName,
msg:'文件写入成功'
})
return
}
writeFileSync(fileName, file.data);
res.send({
code: 200,
msg: "文件创建并写入成功",
});
});

app.listen(PORT, () => {
console.log(`server running in ${PORT}`);
});

 

以上就实现了大文件上传的基本方法,像文件类型校验啥的可自行扩展,本demo只是基本示例,如有更好的方法,可在评论区留下讨论,共同进步~

 

参考文章:http://blog.ncmem.com/wordpress/2023/09/24/%e5%a4%a7%e6%96%87%e4%bb%b6%e5%88%87%e7%89%87%e4%b8%8a%e4%bc%a0%e6%96%ad%e7%82%b9%e7%bb%ad%e4%bc%a0%e8%a7%a3%e5%86%b3%e6%96%b9%e6%a1%88-%e5%89%8d%e5%90%8e%e7%ab%af%e5%ae%9e%e7%8e%b0/

欢迎入群一起讨论

 

 

标签:uploaded,断点续传,const,文件,切片,let,file,上传
From: https://www.cnblogs.com/songsu/p/17725770.html

相关文章

  • PbootCMS附件上传报错UNKNOW: Code: 8192; Desc: stripos()
    PbootCMS附件上传报错UNKNOW:Code:8192;Desc:stripos(),具体显示如下图所示:解决方法:打开/core/function/file.php,找到以下代码:1if (stripos($types,$ext)!== false)改为如下代码:1if (stripos($types,chr($ext))!== false)......
  • springBoot上传文件时MultipartFile报空问题解决方法
    1.问题描述:之前用springMVC,转成springboot之后发现上传不能用。网上参考说是springboot已经有CommonsMultipartResolver了,但是我的上传后台接收的还是null。2.解决方法加入配置类importorg.springframework.context.annotation.Bean;importorg.springframework.context......
  • spring boot实现切割分片上传
    文件上传是web开发中经常会遇到的springboot的默认配置为10MB,大于10M的是传不上服务器的,需要修改默认配置但是如果修改支持大文件又会增加服务器的负担。当文件大于一定程度时,不仅服务器会占用大量内存,而且http传输极可能会中断。可以采用切割分片上传html5提供的文件API中可......
  • 搭建Wpf框架(17) ——大文件上传与下载
    先上效果图:大文件上传1.客户端需要按照块拆成一块一块,先计算大小,然后计算块的个数,然后按块逐个上传,代码如下:public async Task<UploadResult> UploadFileChunck(string path, Action<double> progressAction)        {            try      ......
  • 文件的上传和下载
    文件的上传1.我们先测试打通服务器upload.jsp负责文件的上传<%--CreatedbyIntelliJIDEA.User:SWTDate:2023/9/22Time:18:39TochangethistemplateuseFile|Settings|FileTemplates.--%><%@pagecontentType="text/html;charset=UTF-8"lan......
  • 大文件上传之--切片上传和断点续传
    <template>  <div id="app">    <el-upload      drag      action      :auto-upload="false"      :show-file-list="false"      :on-change="changeFile"    >      <i class="el-icon-upload"&g......
  • 大文件切片上传和断点续传
    大文件分片上传前端知识点md5加密算法用于确保信息传输完整一致sparkmd5在散列大量数据(例如文件)时表现得更好。可以使用FileReader和Blob读取块中的文件,并将每个块附加到md5//创建一个sparkmd5计算arrayBuffer的对象spark=newSparkMD5.ArrayBuffer()//添加到arrayb......
  • 前端上传大文件处理(切片、断点续传)
    思路1.对文件做切片,即将一个请求拆分成多个请求,每个请求的时间就会缩短,且如果某个请求失败,只需要重新发送这一次请求即可,无需从头开始2.通知服务器合并切片,在上传完切片后,前端通知服务器做合并切片操作3.控制多个请求的并发量,防止多个请求同时发送,造成浏览器内存溢出,导致页......
  • 大文件断点续传、快传秒传实现方案
    前言为什么视频、音频、大型文档等大文件不能也直接上传吗,简单又方便?遇到手动暂停、网络中断、网络不稳定或者服务端响应超时,当你终于半天到99%,网络突然断开喜提从0%再来一次再者一次服务接受如此大的数据传输,不说服务器肯同意接收,即使配置同意接受这常常会使服务器出现响应超时......
  • 如何实现大文件断点续传、秒传
    大家先来了解一下几个概念:「文件分块」:将大文件拆分成小文件,将小文件上传\下载,最后再将小文件组装成大文件;「断点续传」:在文件分块的基础上,将每个小文件采用单独的线程进行上传\下载,如果碰到网络故障,可以从已经上传\下载的部分开始继续上传\下载未完成的部分,而没有必要从头开始......