实现 Vue 大文件上传和断点续传需要掌握以下几个步骤:
- 分片:将大文件分割成若干个小块,便于上传。一般采用 Blob 对象或 ArrayBuffer 来实现。
- 上传:将分片文件上传到服务器。可以使用 XMLHttpRequest、Fetch 等工具进行上传。
- 断点续传:如果上传失败或上传过程中断开连接,需要记录已上传的分片,下次上传时跳过已上传的分片。
- 合并:上传完成后,将所有分片文件合并成一个完整的文件。
以下是一个例子,展示如何使用 Vue.js 实现大文件上传和断点续传:
- 安装依赖
首先需要安装一些依赖,包括 axios、js-sha256 等,可以使用 npm 或 yarn 进行安装:
npm install axios js-sha256
- 分片和上传
在前端实现分片和上传时需要考虑以下几个问题:
- 如何分片:可以根据文件大小或自定义的分片大小进行分割,一般使用 Blob 对象或 ArrayBuffer 储存。
- 如何上传:可以使用 XMLHttpRequest、Fetch 等工具进行上传,需要在请求头中添加一些信息,如文件名、片数、当前片数、是否续传等。
以下是一个使用 axios 进行上传的示例代码:
const uploadFile = (file) => {
const chunkSize = 4 * 1024 * 1024; // 4MB
const fileSize = file.size;
const chunks = Math.ceil(fileSize / chunkSize);
const sha256Promise = sha256(file);
const config = {
headers: {
'Content-Type': file.type,
'X-File-Name': encodeURIComponent(file.name),
'X-File-Size': fileSize,
'X-File-Chunks': Math.ceil(fileSize / chunkSize),
'X-File-Hash': '',
},
};
return sha256Promise.then(hash => {
config.headers['X-File-Hash'] = hash;
let promises = [];
for (let i = 0; i < chunks; i++) {
const start = i * chunkSize;
const chunk = file.slice(start, start + chunkSize);
const formData = new FormData();
formData.append('chunk', chunk);
formData.append('chunkNumber', i + 1);
formData.append('chunksTotal', chunks);
promises.push(
axios.post('/api/upload', formData, config)
);
}
return axios.all(promises);
});
};
- 断点续传
在上传过程中发生中断或失败时,需要从中断点处继续上传。为实现断点续传,需要在服务器端记录已上传的分片,前端发送请求时携带这些信息,服务器判断后返回还需要上传哪些分片。如果没有中断,需要检查文件是否已完整上传。
以下是一个使用 axios 进行断点续传的示例代码:
const uploadFile = (file) => {
const chunkSize = 4 * 1024 * 1024; // 4MB
const fileSize = file.size;
const chunks = Math.ceil(fileSize / chunkSize);
const sha256Promise = sha256(file);
let config = {
headers: {
'Content-Type': file.type,
'X-File-Name': encodeURIComponent(file.name),
'X-File-Size': fileSize,
'X-File-Chunks': Math.ceil(fileSize / chunkSize),
'X-File-Hash': '',
},
};
const checkUploadedChunks = () => {
return axios.post('/api/check', {
filename: encodeURIComponent(file.name),
filesize: fileSize,
filechunks: Math.ceil(fileSize / chunkSize),
}).then(response => {
return response.data;
});
};
return sha256Promise.then(hash => {
config.headers['X-File-Hash'] = hash;
return checkUploadedChunks();
}).then(uploadedChunks => {
if (uploadedChunks.length === chunks) {
return Promise.resolve();
}
const formData = new FormData();
for (let i = 0; i < chunks; i++) {
if (uploadedChunks.includes(i + 1)) {
continue;
}
const start = i * chunkSize;
const chunk = file.slice(start, start + chunkSize);
formData.append('chunk', chunk);
formData.append('chunkNumber', i + 1);
formData.append('chunksTotal', chunks);
}
return axios.post('/api/upload', formData, config);
});
};
- 合并
当所有分片都上传完成之后,需要在服务器端对这些分片进行合并,生成完整的文件。如果中间有分片上传失败或中断,需要在下次上传时跳过这些分片。
以下是一个使用 Node.js 进行合并的示例代码:
const fs = require('fs');
const path = require('path');
const mergeChunks = (form) => {
const filename = decodeURIComponent(form.get('filename'));
const fileSize = form.get('filesize');
const chunksTotal = form.get('filechunks');
const tempDir = path.join('temp', filename);
const chunks = Array.from(form.entries())
.filter(([key, value]) => key.startsWith('chunk-'))
.map(([key, value]) => {
const number = parseInt(key.slice(6), 10);
const chunkFilePath = path.join(tempDir, `${filename}.${number}`);
return {
number,
filename: chunkFilePath,
size: value.length,
};
})
.sort((a, b) => a.number - b.number);
if (chunks.length !== chunksTotal) {
console.log(`文件[${filename}]分片数量[${chunks.length}]不符要求[${chunksTotal}]`);
return Promise.reject();
}
const writeStream = fs.createWriteStream(path.join('uploads', filename));
return new Promise((resolve, reject) => {
let offset = 0;
const doWrite = () => {
const chunk = chunks.shift();
if (!chunk) {
writeStream.end();
console.log(`文件[${filename}]已写入`);
resolve();
return;
}
const readStream = fs.createReadStream(chunk.filename, { highWaterMark: chunk.size });
readStream.pipe(writeStream, { end: false });
readStream.on('error', reject);
readStream.on('end', () => {
console.log(`分片[${chunk.number}]已写入`);
offset += chunk.size;
doWrite();
});
};
doWrite();
});
};
完整的示例代码可以从我的 GitHub 中获取:
- 前端:https://github.com/purple4pur/file-transfer-frontend
- 后端:https://github.com/purple4pur/file-transfer-backend
以上是详细讲解“Vue 大文件上传和断点续传的实现”的攻略,提供了代码示例和一些关键步骤的解释,希望能对你有所帮助。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Vue 大文件上传和断点续传的实现 - Python技术站