前端大文件上传分片、断点续传
const chunkSize = 1024 * 1024 // 1MB
function createChunks(file) {
const chunks = []
let start = 0
while (start < file.size) {
chunks.push(file.slice(start, start + chunkSize))
start += chunkSize
}
return chunks
}
为什么需要 hash/md5?
- 校验文件完整性
- 避免重复上传
前端如何计算 hash?
npm i spark-md5
import SparkMD5 from 'spark-md5'
async function calculateHash(file: 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 as ArrayBuffer)
resolve(spark.end())
}
})
}
查询已上传分片
const res = await fetch(`/check?hash=${fileHash}`)
const uploadedChunks = await res.json()//[0,1,2]
只上传缺失部分
async function uploadFile(file) {
const chunks = createChunks(file)
const uploadedChunks = await getUploadedChunks()
for (let index = 0; index < chunks.length; index++) {
//核心
if (uploadedChunks.includes(index)) {
continue
}
const formData = new FormData()
formData.append('file', chunks[index])
formData.append('hash', fileHash)
formData.append('index', index)
await fetch('/upload', {
method: 'POST',
body: formData
})
}
await mergeChunks()
}
通知后端合并
await fetch('/merge', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
hash: fileHash,
fileName: file.name
})
})
上传进度怎么算?
onUploadProgress中拿到loaded和total
现代框架用哪些库?
ali-oss
import OSS from 'ali-oss'
const client = new OSS({
region: 'oss-cn-hangzhou',
accessKeyId: 'xxx',
accessKeySecret: 'xxx',
bucket: 'test',
})
await client.multipartUpload(
file.name,
file,
{
parallel: 4,
partSize: 1024 * 1024,
progress(p) {
console.log(p)
},
}
)
simple-uploader.js
<template>
<uploader
:options="options"
@file-success="fileSuccess"
>
<uploader-btn>选择文件</uploader-btn>
<uploader-list />
</uploader>
</template>
<script setup>
const options = {
target: '/api/upload',
chunkSize: 2 * 1024 * 1024,
testChunks: true
}
function fileSuccess() {
console.log('上传完成')
}
</script>
