vue实现切片上传
切片上传的实现原理
切片上传是将大文件分割成多个小块(切片)分别上传,最后在服务端合并。这种方式能提高上传效率、支持断点续传和并发上传。

前端实现步骤
使用Vue实现切片上传需要借助File对象的slice方法分割文件,配合axios或fetch发送请求。
<template>
<input type="file" @change="handleFileChange" />
<button @click="uploadFile">上传</button>
</template>
<script>
export default {
data() {
return {
file: null,
chunkSize: 2 * 1024 * 1024, // 2MB每片
};
},
methods: {
handleFileChange(e) {
this.file = e.target.files[0];
},
async uploadFile() {
if (!this.file) return;
const chunks = this.createChunks(this.file);
await this.uploadChunks(chunks);
},
createChunks(file) {
const chunks = [];
let start = 0;
while (start < file.size) {
const end = Math.min(start + this.chunkSize, file.size);
chunks.push({
chunk: file.slice(start, end),
index: chunks.length,
total: Math.ceil(file.size / this.chunkSize),
filename: file.name,
});
start = end;
}
return chunks;
},
async uploadChunks(chunks) {
const requests = chunks.map((item) => {
const formData = new FormData();
formData.append('chunk', item.chunk);
formData.append('index', item.index);
formData.append('total', item.total);
formData.append('filename', item.filename);
return axios.post('/upload', formData, {
headers: { 'Content-Type': 'multipart/form-data' },
});
});
await Promise.all(requests);
this.mergeChunks();
},
async mergeChunks() {
await axios.post('/merge', {
filename: this.file.name,
total: Math.ceil(this.file.size / this.chunkSize),
});
},
},
};
</script>
关键点说明
- 文件分割:通过
File.prototype.slice方法将文件切割成指定大小的块。 - 并发上传:使用
Promise.all并发上传所有切片。 - 合并请求:所有切片上传完成后,发送合并请求通知服务端。
服务端处理逻辑
服务端需要实现两个接口:
- 接收切片并临时存储
- 合并所有切片为完整文件
// Node.js示例(Express框架)
const express = require('express');
const fs = require('fs');
const multer = require('multer');
const path = require('path');
const app = express();
const upload = multer({ dest: 'temp/' });
app.post('/upload', upload.single('chunk'), (req, res) => {
const { index, filename } = req.body;
const chunkPath = path.join('temp', `${filename}-${index}`);
fs.renameSync(req.file.path, chunkPath);
res.send({ success: true });
});
app.post('/merge', async (req, res) => {
const { filename, total } = req.body;
const filePath = path.join('uploads', filename);
const writeStream = fs.createWriteStream(filePath);
for (let i = 0; i < total; i++) {
const chunkPath = path.join('temp', `${filename}-${i}`);
const chunk = fs.readFileSync(chunkPath);
writeStream.write(chunk);
fs.unlinkSync(chunkPath);
}
writeStream.end();
res.send({ success: true });
});
优化方向
- 进度显示:通过
axios的onUploadProgress回调实现上传进度显示。 - 断点续传:记录已上传的切片索引,下次上传时跳过。
- 错误重试:对失败的请求进行自动重试。
- 文件校验:上传前后通过MD5校验文件完整性。
注意事项
- 切片大小需根据网络状况调整,通常2-5MB为宜。
- 服务端临时目录需要定期清理未合并的切片。
- 合并文件时注意内存限制,大文件建议使用流式合并。







