JS实现OSS断点续传
先说场景:
用户上传一个视频,但可能因为网络波动或视频较大浏览器的处理偶尔出错,导致上传失败或中断时,可以点击重试,自动接着刚刚上传到的位置继续上传,这就是断点续传。
实现效果:
页面结构:
第一部分:
上传进度提示:上传中+进度条,上传成功,上传失败+重试
<div class="loading" v-if="progressShow"><div class="progress-demo"><div class="progress-content"><div class="progress-content-des"><div class="progress-content-des-title" v-if="uploadRes === 0">上传中</div><div class="progress-content-des-title" v-else-if="uploadRes === 1"><tiny-icon-successful /><div style="color: #09aa71;">上传成功</div></div><div class="progress-content-des-title" v-else-if="uploadRes === 2"><tiny-icon-fail /><div style="color: #f56c6c;">上传失败</div><tiny-button type="success" @click="artUploadRetry(checkpoint, upload_file)">重试</tiny-button></div><div class="progress-content-des-title" v-else>上传进度</div></div><tiny-progress class="progress" type="line" :percentage="percentage" :stroke-width="12" /></div></div>
</div>
样式部分可以根据实际情况进行调整,这里不过多赘述:
.progress-demo {display: flex;
}.progress-content {flex: 1;
}.progress-content-des {display: flex;justify-content: space-between;margin-bottom: 8px;
}.progress-content-des-title {display: flex;align-items: center;justify-content: left;height: 20px;line-height: 20px;font-size: 14px;
}.progress :deep(.tiny-progress__text) {font-size: 12px !important;
}.tiny-icon-successful {fill: #09aa71;margin-right: 4px;
}.tiny-icon-fail {fill: #f56c6c;margin-right: 4px;
}
第二部分:
上传按钮,视频预览
<tiny-button @click="uploadArt" :disabled="uploadDisabled">作品上传</tiny-button><div v-if="video_url" class="video-preview-container"><video class="preview-video" controls :src="video_url" />
</div>
变量定义:
const percentage = ref(0)
const uploadRes = ref(4)
const uploadDisabled = ref(false)
const video_url = ref('')
let checkpoint = null
核心函数:
第一部分:
设置oss上传的入参,checkpoint为断点,partSize为分片大小,parallel为并发数:
const commonUpload = async (c_p, file) => {try {uploadRes.value = 0return await client.multipartUpload(object_name, file, {parallel: 2,partSize: 1024 * 1024,checkpoint: c_p,timeout: 120000,progress: (per, cp, res) => {percentage.value = Number((per * 100).toFixed(2))checkpoint = cp}})} catch (err) {console.log(err)uploadRes.value = 2uploadDisabled.value = falsereturn null}
}
第二部分:
视频上传校验及上传进度展示(代码关键位置可查看注释)
const uploadArt = () => {const inputFile = document.createElement('input')inputFile.type = 'file'inputFile.accept = 'video/*'inputFile.multiple = falseinputFile.addEventListener('change', async (event) => {const files = event.target.filesif (!files || files.length === 0) returnconst file = files[0]if (!file.name.endsWith('.mp4') && !file.name.endsWith('.mov')) {Modal.message({status: 'error',message: '请上传.mov或.mp4格式的视频!',duration: 3000})return}if (file.size > 300 * 1024 * 1024) {Modal.message({status: 'error',message: '视频不能大于300MB!',duration: 3000})return}upload_file.value = file // 存储当前这个文件,为了后面断点续传使用filevideo_url.value = '' // 重置视频地址progressShow.value = trueuploadDisabled.value = trueuploadRes.value = 0 // 重置视频上传状态percentage.value = 0 // 重置进度条状态checkpoint = null // 重置断点const ext = file.name.split('.').pop()await getToken(ext) // 获取桶信息const res = await commonUpload(checkpoint, file) // 调用OSS上传if(res) {video_url.value = window.sessionStorage.getItem("video_url") // 这里是从OSS处获取存储到sessionStorage里面的(后端返回的数据)uploadRes.value = 1uploadDisabled.value = false} else {uploadRes.value = 2uploadDisabled.value = false}});inputFile.click();
}
关于代码中,getToken()和OSS的封装在前面的文章有提到,文章地址:
实现视频分片上传 OSS_delphi7如何将视频上传到oss-CSDN博客
这里对这部分代码进行贴图:
第三部分:
重试函数:通过存储的断点位置调用 commonUpload 继续上传,这里不要再次调用getToken(),因为会重新获取到桶信息,用之前的才可以继续上传,否则会导致与之前的桶信息不一致而报错。
const artUploadRetry = async (c_p, file) => {const res = await commonUpload(c_p, file)if(res) {video_url.value = window.sessionStorage.getItem("video_url")uploadRes.value = 1uploadDisabled.value = false} else {uploadRes.value = 2uploadDisabled.value = false}
}
其他一:
这里如果想测试上传失败,可以用浏览器自带的网络限制,可以自定义网速:
点击 Add 即可自定义,填写内容如下:
其他二:
如果是上传图片或者其他小文件,没用到 OSS,也想给用户展示上传进度,可以写一个方法:
const getTimer = () => {uploadRes.value = 0percentage.value = 0process.value = setInterval(() => {if (percentage.value < 95) {percentage.value += 5} else {clearInterval(process.value)}}, 1000)
}
在小于95%之前会每秒+5%, 在上传的方法中,获取到上传成功结果之后将 percentage.value = 100 即可,如果上传失败不需要将 percentage.value = 0。比如: