下面是我对“Vue+Node实现大文件上传和断点续传”的攻略的详细讲解:
1.前端资源准备
首先我们需要在前端准备好相关的资源,比如上传页面和相关的组件,这里推荐使用Vue。
1.1 安装依赖
因为我们使用了Vue框架,所以我们需要安装Vue相关的依赖。
npm install vue --save
1.2 创建组件
我们需要创建一个上传组件,这里我们使用vue-cli
脚手架来创建。
vue create upload-component
创建成功后,我们需要在App.vue
中添加上传页面和相关逻辑。
<template>
<div class="container">
<h1>文件上传</h1>
<input type="file" @change="uploadFile">
</div>
</template>
<script>
export default {
methods: {
async uploadFile(event) {
const file = event.target.files[0];
const response = await this.$http.post('/upload', file);
console.log(response);
},
},
};
</script>
1.3 安装axios
我们还需要安装axios进行网络请求。
npm install axios --save
2.Node服务端实现
在前端准备好了相关资源后,我们需要在后端完成相关逻辑,这里我们使用Node作为后端。
2.1 安装依赖
因为我们使用了Node作为后端,所以我们需要安装相关的依赖。
npm init -y
npm install express multer --save
其中,express
用于搭建服务器,multer
用于处理上传的文件。
2.2 创建服务端
我们需要创建一个服务端,并在其中实现上传接口和相关逻辑。
const express = require('express');
const multer = require('multer');
const app = express();
// 创建一个Multer对象
const upload = multer();
// 上传接口
app.post('/upload', upload.single('file'), (req, res) => {
console.log(req.file);
res.send('上传成功');
});
const server = app.listen(3000, () => {
console.log('服务器启动成功');
});
2.3 实现文件切片
大文件上传时,我们需要将文件切片后分多次上传。为此,我们需要将上传的文件进行切片。
/**
* 按照指定的大小切割文件
* @param {File} file 文件
* @param {number} chunkSize 切割后每个文件的大小
* @returns {Blob[]} 文件切片
*/
function splitFile(file, chunkSize) {
const chunks = [];
for (let offset = 0; offset < file.size; ) {
const chunk = file.slice(offset, offset + chunkSize);
chunks.push(chunk);
offset += chunkSize;
}
return chunks;
}
2.4 实现文件合并
因为我们实现了文件切片,所以在上传完成时,我们还需要将所有切片进行合并,组成完整的文件。
/**
* 合并切割的文件
* @param {Blob[]} chunks 文件切片
* @returns {Promise<Blob>} 合并后的文件
*/
function mergeChunks(chunks) {
return new Promise((resolve) => {
const file = new Blob(chunks, { type: chunks[0].type });
resolve(file);
});
}
2.5 实现文件保存
上传完成后,我们需要将文件进行保存。这里我们简单起见,将文件保存在服务器本地。
/**
* 保存文件
* @param {Blob} file 文件
* @returns {Promise<string>} 文件路径
*/
function saveFile(file) {
return new Promise((resolve, reject) => {
const date = new Date();
const year = date.getFullYear();
const month = date.getMonth() + 1;
const day = date.getDate();
const fileName = `${year}-${month}-${day}-${file.name}`;
const filePath = `./uploads/${fileName}`;
const reader = new FileReader();
reader.readAsArrayBuffer(file);
reader.onloadend = () => {
const buffer = Buffer.from(reader.result);
fs.writeFile(filePath, buffer, (err) => {
if (err) {
reject(err);
} else {
resolve(filePath);
}
});
};
});
}
2.6 实现断点续传
大文件上传时,因为上传时间过长,可能会出现断网、断电等情况。为了避免这种情况下需要重新上传的问题,我们需要实现断点续传功能。
/**
* 判断文件是否已经上传过
* @param {string} filePath 文件路径
* @returns {Promise<number>} 已上传的文件大小
*/
function getFileSize(filePath) {
return new Promise((resolve, reject) => {
fs.stat(filePath, (err, stat) => {
if (err) {
reject(err);
} else {
resolve(stat.size);
}
});
});
}
/**
* 上传接口
*/
app.put('/upload', upload.single('file'), async (req, res) => {
const file = req.file;
const filePath = `./uploads/${req.query.name}`;
try {
// 如果文件已经存在,则发送已上传的大小
if (fs.existsSync(filePath)) {
const uploadedSize = await getFileSize(filePath);
res.send({
code: 2,
uploadedSize,
});
return;
}
// 获取上传的总大小
const fileSize = Number(req.query.size);
// 切割文件
const chunks = splitFile(file.buffer, CHUNK_SIZE);
console.log('开始上传');
// 将切割后的文件上传到七牛云
for (let i = 0; i < chunks.length; i++) {
const chunk = chunks[i];
const chunkIndex = i + 1;
const key = `${req.query.name}.part${chunkIndex}`;
const result = await uploadToQiniu(chunk, key);
console.log(`上传成功:${key}`);
}
// 合并文件
const mergedFile = await mergeChunks(chunks);
// 保存文件
const fileUrl = await saveFile(mergedFile);
console.log(`上传完成:${fileUrl}`);
res.send('上传成功');
} catch (err) {
console.error(err);
res.status(500);
res.send({ error: err.message });
}
});
3.示例说明
下面给出两个简单的示例说明。
示例一
以上传视频文件为例,视频文件大小为5GB
,我们需要将视频切割成一个个大小为1GB
的文件进行上传。
在前端,我们需要创建上传组件,并将上传的文件进行切割后发送给后端。
在后端,我们需要先判断文件是否已经上传过,如果已经上传过,则返回已上传的大小;否则,我们需要将切割后的文件发送到七牛云进行上传,上传完成后再将所有切片进行合并并保存。
示例二
以上传图片为例,我们需要实现断点续传的功能。假设现在我们已经上传了一个大小为1MB
的图片到服务器,但是由于网络中断,导致上传失败。现在我们重新上传图片,这时我们需要检查服务器上是否已经存在这张图片了,如果存在,我们只需要上传未上传的部分即可。如果不存在,我们需要将整个图片上传到服务器。
在前端,我们需要获取本地图片的sha1值以及已上传的大小,然后发送给服务端。
在后端,我们需要根据前端发送过来的sha1值查询数据库,判断图片是否存在。如果存在,我们只需要上传未上传的部分;如果不存在,我们需要将整个图片上传到服务器。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Vue+Node实现大文件上传和断点续传 - Python技术站