首页 > 其他分享 >文件上传 切片与断点续传

文件上传 切片与断点续传

时间:2023-09-25 09:22:48浏览次数:28  
标签:断点续传 return 文件 data upload 切片 file 上传

主要讲前端 ,后端使用node。会写一下后端的处理
1.单个文件上传
请求头为 multipart/form-data
数据为 from-data格式

let formData = new FormData();
formData.append('file', _file);
formData.append('filename', _file.name);

然后使用post直接给后端。后端直接存起来

2.单个文件使用base64格式上传(针对于图片)
在拿到文件后

// 把选择的文件读取成为BASE64
const changeBASE64 = file => {
return new Promise(resolve => {
let fileReader = new FileReader();
fileReader.readAsDataURL(file);
fileReader.onload = ev => {
resolve(ev.target.result);
};
});
};
BASE64 = await changeBASE64(file);

这里使用了一个内置类为 FileReader ,readAsDataURL方法是编为base64,也还有别的编码 比如二进制
fileReader.onload 是一个异步事件。这里封装了一个promise

instance 是一个axios实例
为了防止乱码,这里为了防止乱码使用encodeURIComponent做了一个编码,记得让后端解码呀

data = await instance.post('/upload_single_base64', {
file: encodeURIComponent(BASE64),
filename: file.name
}, {
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
}
});

针对这个功能一个小提示 就是如果你同一个文件 上传第二次的时候,后端会提示你文件存在(这是优化点,后端可以不做也行)

后端处理

// 单文件上传处理「BASE64」
app.post('/upload_single_base64', async (req, res) => {
let file = req.body.file,
filename = req.body.filename,
spark = new SparkMD5.ArrayBuffer(), //SparkMD5 第三方 实例化一个对象
suffix = /\.([0-9a-zA-Z]+)$/.exec(filename)[1], // 获取文件类型
isExists = false,
path;
file = decodeURIComponent(file); // 解码
file = file.replace(/^data:image\/\w+;base64,/, ""); // 提取base64的内容
file = Buffer.from(file, 'base64'); // 二进制转换
spark.append(file); // 添加文件进行分析
path = `${uploadDir}/${spark.end()}.${suffix}`; //生成唯一hash文件名 spark.end()
await delay();
// 检测是否存在
isExists = await exists(path); // 根据文件名判断是否存在
if (isExists) {
res.send({
code: 0,
codeText: 'file is exists',
originalFilename: filename,
servicePath: path.replace(__dirname, HOSTNAME)
});
return;
}
writeFile(res, path, file, filename, false);
});


// 检测文件是否存在
const exists = function exists(path) {
return new Promise(resolve => {
fs.access(path, fs.constants.F_OK, err => {
if (err) {
resolve(false);
return;
}
resolve(true);
});
});
};

 

一般这个是后端处理,但是不排除让你自己来。了解一下机制就行

3.缩略图处理 ,并上传

请求头为 multipart/form-data
数据为 from-data格式
1.缩略图 的话是前端把文件转成base64地址,然后使用src属性

上传的时候,前端进行文件名的hash 处理,后端不处理

主要是先把文件转成二进制 再 使用 SparkMD5插件

const changeBuffer = file => {
return new Promise(resolve => {
let fileReader = new FileReader();
fileReader.readAsArrayBuffer(file);
fileReader.onload = ev => {
let buffer = ev.target.result,
spark = new SparkMD5.ArrayBuffer(),
HASH,
suffix;
spark.append(buffer);
HASH = spark.end();
suffix = /\.([a-zA-Z0-9]+)$/.exec(file.name)[1];
resolve({
buffer,
HASH,
suffix,
filename: `${HASH}.${suffix}`
});
};
});
};

这样后端就只要判断就行,不会进行处理
后端处理
multiparty_upload 用来解析 fromdata 格式 。

4 文件上传进度监控
这里主要是用到了axios中的 onuploadProgress 实现

try {
let formData = new FormData();
formData.append('file', file);
formData.append('filename', file.name);
data = await instance.post('/upload_single', formData, {
// 文件上传中的回调函数 xhr.upload.onprogress
onUploadProgress(ev) {
let {
loaded,
total
} = ev;
upload_progress.style.display = 'block';
upload_progress_value.style.width = `${loaded/total*100}%`;
}
});
if (+data.code === 0) {
upload_progress_value.style.width = `100%`;
await delay(300);
alert(`恭喜您,文件上传成功,您可以基于 ${data.servicePath} 访问该文件~~`);
return;
}
throw data.codeText;
} catch (err) {
alert('很遗憾,文件上传失败,请您稍后再试~~');

主要代码和单一文件的上传没有太大区别,只是多了一个axios回调
loaded是已上传 大小 total是总大小

// 延迟函数
const delay = function delay(interval) {
typeof interval !== "number" ? interval = 1000 : null;
return new Promise(resolve => {
setTimeout(() => {
resolve();
}, interval);
});
};

这里设置了一个延时函数,是因为过渡是有一个动画效果 所以为了顺滑再最后一个100% 动画完成后,再进行提示 (这个自己根据情况去设置)

5 多文件上传,进度监控
input 要设置 多选属性

主要是一个循环去发送请求,去监听上传进度,再用promise.all 去进行后续的一些处理工作

6 拖拽文件上传

这里用到了几个特殊事件

// 拖拽获取 dragenter dragleave dragover drop
/* upload.addEventListener('dragenter', function () {
console.log('进入');
});
upload.addEventListener('dragleave', function () {
console.log('离开');
}); */
upload.addEventListener('dragover', function (ev) {
ev.preventDefault();
});
upload.addEventListener('dragover', function (ev) {
ev.preventDefault();
let file = ev.dataTransfer.files[0];
if (!file) return;
uploadFile(file);
});

这里主要是使用drop事件,这里注意需要禁止dragover drop默认事件。因为浏览器会默认打开文件
文件得获取为 ev.dataTransfer.files

后续得上传操作就没啥,和别的没啥大区别

7 大文件得切片上传和断点续传

断点续传是要基于切片上传
切片上传后,文件的合并时由服务端根据 文件的hash名来进行的
这个文件的hash 可以由客户端来做,当然后端来也是可以的,这里是客户端来做
每次上传之前。我们都需要先把需要上传的文件hash 名给后端。后端返回我们已经上传过的切片数组,然后我们固定大小或者固定数量来进行切片 。这里是把两者结合了
然后开始循环切片数组,发送请求之前 先判断是否在已上传过的数组里面,如果纯在的话我们就不需要进行请求
在所有的请求都完成后,也就是我们的进度变为100% 我们再告知客户端,可以进行切片的合并了

upload_inp.addEventListener('change', async function () {
let file = upload_inp.files[0];
if (!file) return;
upload_button_select.classList.add('loading');
upload_progress.style.display = 'block';

// 获取文件的HASH
let already = [],
data = null,
{
HASH,
suffix
} = await changeBuffer(file);

// 获取已经上传的切片信息
try {
data = await instance.get('/upload_already', {
params: {
HASH
}
});
if (+data.code === 0) {
already = data.fileList;
}
} catch (err) {}

// 实现文件切片处理 「固定数量 & 固定大小」
let max = 1024 * 100,
count = Math.ceil(file.size / max),
index = 0,
chunks = [];
if (count > 100) {
max = file.size / 100;
count = 100;
}
while (index < count) {
chunks.push({
file: file.slice(index * max, (index + 1) * max),
filename: `${HASH}_${index+1}.${suffix}`
});
index++;
}

// 上传成功的处理
index = 0;
const clear = () => {
upload_button_select.classList.remove('loading');
upload_progress.style.display = 'none';
upload_progress_value.style.width = '0%';
};
const complate = async () => {
// 管控进度条
index++;
upload_progress_value.style.width = `${index/count*100}%`;

// 当所有切片都上传成功,我们合并切片
if (index < count) return;
upload_progress_value.style.width = `100%`;
try {
data = await instance.post('/upload_merge', {
HASH,
count
}, {
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
}
});
if (+data.code === 0) {
alert(`恭喜您,文件上传成功,您可以基于 ${data.servicePath} 访问该文件~~`);
clear();
return;
}
throw data.codeText;
} catch (err) {
alert('切片合并失败,请您稍后再试~~');
clear();
}
};

// 把每一个切片都上传到服务器上
chunks.forEach(chunk => {
// 已经上传的无需在上传
if (already.length > 0 && already.includes(chunk.filename)) {
complate();
return;
}
let fm = new FormData;
fm.append('file', chunk.file);
fm.append('filename', chunk.filename);
instance.post('/upload_chunk', fm).then(data => {
if (+data.code === 0) {
complate();
return;
}
return Promise.reject(data.codeText);
}).catch(() => {
alert('当前切片上传失败,请您稍后再试~~');
clear();
});
});
});

 基本上就这么多了,主要是对文件的处理 以及几个获取文件的事件 思路基本上都差不多,很好理解

 

参考文章:http://blog.ncmem.com/wordpress/2023/09/25/%e6%96%87%e4%bb%b6%e4%b8%8a%e4%bc%a0-%e5%88%87%e7%89%87%e4%b8%8e%e6%96%ad%e7%82%b9%e7%bb%ad%e4%bc%a0/

欢迎入群一起讨论

 

标签:断点续传,return,文件,data,upload,切片,file,上传
From: https://www.cnblogs.com/songsu/p/17727146.html

相关文章

  • Tomcat--文件上传--文件包含--(CVE-2017-12615)&&(CVE-2020-1938)
    Tomcat--文件上传--文件包含--(CVE-2017-12615)&&(CVE-2020-1938)复现环境采用Vulfocus靶场环境进行复现,搭建操作和文章参考具体搭建教程参考vulfocus不能同步的解决方法/vulfocus同步失败。CVE-2017-12615文件上传漏洞简介当存在漏洞的Tomcat运行在Windows/Linux主机上,且......
  • 大文件切片上传+断点续传解决方案-前后端实现
    上传文件大家应该都做过,前端直接把file文件传给后端就ok了,但是大文件这样传就会造成页面假死,体验极差。如果遇到网络不稳定的时候,中途上传失败的话,又要从头开始传,本来文件就大,还慢。所以今天我们用一种新方法-切片上传+断点续传前端实现:页面上很简单,我就放了进度条和一个上传文件......
  • 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.控制多个请求的并发量,防止多个请求同时发送,造成浏览器内存溢出,导致页......