1、准备好一个简单的上传结构
<template>
<el-upload
class="upload-demo"
action="#"
:http-request="onHttpRequest"
>
<el-button size="small" type="primary">点击上传</el-button>
</el-upload>
</template>
<script>
export default {
data () {
return {
}
},
created () {
},
methods: {
onHttpRequest () {
console.log(123)
}
}
}
</script>
2、把对象分割成多个文件流切片;固定数量 && 固定大小
onHttpRequest ({ file }) {
console.log(file.size)
// 每块大小
const chunkSize = 5 * 1024
// 切割次数
const chunkCount = Math.ceil(file.size / chunkSize)
// 文件切片 不是数组的slice 文件对象原型上的slice方法,继承自 Blob的slice 二进制数据
// 创建一个FormData对象来存储文件片段和相关信息
const formData = new FormData()
for (let i = 0; i < chunkCount; i++) {
formData.append('chunks', file.slice(i * chunkSize, i * chunkSize + chunkSize), '123')
}
this.uploadChunk(formData)
},
3、断点续传
// 切片上传
async uploadChunk (formData) {
const chunk = formData.get('chunks', this.selectChunks)
await axios({
method: 'POST',
url: '/upload',
data: chunk
})
this.selectChunks++
this.uploadChunk(formData)
}
4、合并文件
if (!chunk && this.selectChunks >= formData.getAll('chunks').length) {
await axios({
method: 'GET',
url: '/merge'
})
return
}
5、文件秒传
文件秒传和文件续传不同,文件续传为继续上一次进行上传,而文件秒传为,上传过的文件或者文件切片后端通过标识对比,省略文件传输,如何生成文件标记和文件块标记?文件名字、索引都不是唯一值,真正唯一的是文件内容,所需要根据文件内容生成文件hash,借助spark-md5
5.1 安装 yarn add spark-md5
yarn add spark-md5
5.2 引入和使用
import SparkMd5 from 'spark-md5'
// 创建spark实例
const spark = new SparkMd5.ArrayBuffer()
// 将buffer数据处理为hash
spark.append(buffer)
// 返回hash
const hash = spark.end()
5.3 封装文件的方法
fileParse (file) {
return new Promise(resolve => {
// 创建读取文件的实例对象
const fileReade = new FileReader()
// 借助实例对象的方法读取文件流数据
fileReade.readAsArrayBuffer(file)
// 监听文件流数据读取成功的回调
fileReade.onload = res => {
// res.target.result 就是文件流数据
resolve(res.target.result)
}
})
},
5.4 封装获取 hash 方法
async getFileHash (file) {
const buffer = await this.fileParse(file)
// 创建spark实例
const spark = new SparkMd5.ArrayBuffer()
// 将buffer数据处理为hash
spark.append(buffer)
// 返回hash
return spark.end()
},
5.5 添加 hash
async onHttpRequest ({ file }) {
const fileHash = await this.getFileHash(file)
// 每块大小
const chunkSize = 5 * 1024
// 切割次数
const chunkCount = Math.ceil(file.size / chunkSize)
// 文件切片 不是数组的slice 文件对象原型上的slice方法,继承自 Blob的slice 二进制数据
// 创建一个FormData对象来存储文件片段和相关信息
const formData = new FormData()
for (let i = 0; i < chunkCount; i++) {
const chunk = file.slice(i * chunkSize, i * chunkSize + chunkSize)
const chunkHash = await this.getFileHash(file)
formData.append('chunks', chunk, `${fileHash}:${chunkHash}`)
}
console.log(formData.getAll('chunks'))
// this.uploadChunk(formData)
},
5.6 文件检查
// 文件检查
async checkFileExists (fileHash) {
return axios({
url: '/fileexists?hash=' + fileHash
})
},
const fileHash = await this.getFileHash(file)
await checkFileExists()