vue实现分段上传
实现分段上传的基本思路
分段上传(分片上传)是将大文件分割成多个小块分别上传,最后在服务器合并的技术。这种方式能提高上传稳定性、支持断点续传,并减轻服务器压力。
前端实现步骤
安装依赖
需要axios库处理网络请求,可能用到spark-md5计算文件哈希(用于断点续传标识)。
npm install axios spark-md5
文件分片处理
通过JavaScript的File API将文件切割为多个Blob片段。
// 文件分片函数
function createFileChunks(file, chunkSize = 5 * 1024 * 1024) {
const chunks = []
for (let i = 0; i < file.size; i += chunkSize) {
chunks.push(file.slice(i, i + chunkSize))
}
return chunks
}
计算文件哈希(可选)
使用spark-md5计算文件唯一标识,用于服务端校验和断点续传。
import SparkMD5 from 'spark-md5'
function calculateFileHash(file) {
return new Promise(resolve => {
const spark = new SparkMD5.ArrayBuffer()
const reader = new FileReader()
reader.readAsArrayBuffer(file)
reader.onload = e => {
spark.append(e.target.result)
resolve(spark.end())
}
})
}
上传分片
通过FormData携带分片数据,建议添加分片索引、总片数等元信息。
async function uploadChunk(chunk, index, fileHash) {
const formData = new FormData()
formData.append('chunk', chunk)
formData.append('index', index)
formData.append('hash', fileHash)
formData.append('filename', file.name)
try {
await axios.post('/upload', formData, {
headers: { 'Content-Type': 'multipart/form-data' }
})
} catch (error) {
console.error('上传失败:', error)
}
}
合并请求 所有分片上传完成后,通知服务端合并文件。
function mergeChunks(filename, fileHash, chunkCount) {
return axios.post('/merge', { filename, fileHash, chunkCount })
}
完整组件示例
<template>
<div>
<input type="file" @change="handleFileChange" />
<button @click="handleUpload">上传</button>
<div>进度: {{ progress }}%</div>
</div>
</template>
<script>
import axios from 'axios'
import SparkMD5 from 'spark-md5'
export default {
data() {
return {
file: null,
progress: 0
}
},
methods: {
handleFileChange(e) {
this.file = e.target.files[0]
},
async handleUpload() {
if (!this.file) return
const chunkSize = 5 * 1024 * 1024 // 5MB
const chunks = createFileChunks(this.file, chunkSize)
const fileHash = await calculateFileHash(this.file)
// 检查已上传分片(断点续传)
const { data } = await axios.get('/check', {
params: { hash: fileHash }
})
const uploadedChunks = data.uploaded || []
const requests = chunks.map((chunk, index) => {
if (uploadedChunks.includes(index)) {
this.progress += (100 / chunks.length)
return Promise.resolve()
}
return uploadChunk(chunk, index, fileHash)
.then(() => {
this.progress += (100 / chunks.length)
})
})
await Promise.all(requests)
await mergeChunks(this.file.name, fileHash, chunks.length)
}
}
}
</script>
服务端注意事项
- 临时存储:分片需存储在临时目录,合并后清理
- 并发控制:前端可限制并发上传数(如3-5个并行请求)
- 断点续传:服务端应记录已接收的分片索引
- 合并操作:按分片索引顺序合并文件
优化方向
- 进度显示:分片上传进度和整体进度分开计算
- 错误重试:对失败分片自动重试机制
- 暂停恢复:通过取消axios请求实现暂停功能
- Web Worker:大文件哈希计算放入Worker线程避免界面卡顿







