这是我参与2022首次更文挑战的第4天,活动详情查看:2022首次更文挑战
不知道小伙伴们在上传文件的时候有没有遇到下面2种情况
- 重复上传同一个文件时,后端总会迅速的做出反应,告诉你这个文件已经上传过了,或者上传速度非常快
- 上传一半,因为网络问题或者其他因素导致的暂停上传,重新上传该文件时等待时间比较短
今天我们就来看看这个文件秒传背后的秘密
这两种情况首先在我们的服务端肯定是有存储记录的,记录我们每一次上传的文件,例如我们前面文章提到的 hash,当我们上传的 hash 值在服务端存在那我们是不是就可以直接取服务端的资源,就节省了用户等待上传的时间。那第二种情况呢,是怎么处理的?
先来进行一波分析
- 我们需要在客户端把文件切片,一片一片的上传
- 在异常情况下没有切片没有全部上传,服务端需要告诉我们哪些切片是已经存在的
- 客户端将已经存在的切片过滤出来,上传未上传过切片
有了思路我们把代码给撸起来 还记得我们之前 chunks 这个数组嘛?我们就是把上传的文件进行了切片 这里我们对这个数组进行重组,然后利用 Promise.all() 进行上传
chunks = chunks.map((chunk, index) => {
// 切片的名字 hash+index
const name = hash + '-' + index
return {
hash,
name,
index,
chunk: chunk.file,
progress: 0
}
})
const requests = chunks.value
.map((chunk, index) => {
// 转成promise
const form = new FormData()
form.append('chunk', chunk.chunk)
form.append('hash', chunk.hash)
form.append('name', chunk.name)
return { form, index: chunk.index, error: 0 }
})
.map(({ form, index }) =>
http.post('/api/uploadFileChunks', form, {
onUploadProgress: (progress) => {
// 每个区块有自己的进度条,整体的进度条需要计算
chunks.value[index].progress = Number(((progress.loaded / progress.total) * 100).toFixed(2))
}
})
)
Promise.all(requests)
我们在上传之前是不是还需要看一下服务器端是否有该文件的切片信息
const {
data: { uploaded, uploadedList }
} = await http.post('/api/checkFile', {
hash,
})
// 如果服务端已经存在改文件信息,我们就直接告诉用户上传成功
// 如果只有部分文件我们就返回该文件的切片数组,客户端过滤
if (uploaded) {
return ElMessage.success('秒传成功')
}
客户端过滤就是把上面的请求加一个条件
const requests = chunks.value
.filter((chunk) => uploadedList.indexOf(chunk.name) == -1)
..map((chunk, index) => {
....
剩下的工作就需要交给服务端去做一个切片的整合了,至此文件上传先更新到这里。这个项目在我的 github 上面有完整的代码,需要的同学可以去瞅一瞅