文档直达:服务端签名后直传
没有采用JS客户端签名直传上是因为,此过程AccessKey ID和AcessKey Secret会暴露在前端页面,因此存在严重的安全隐患。所以查找阿里云决定使用服务端签名后直传的方案。
一、功能拆分
视频上传组件 el-upload:
<el-upload
style="marginTop:-5px;"
class="upload-demo"
:action="ossParams.host || ''"
:data="extraData"
:before-upload="beforeUpload"
:on-progress="handleUploadProgress"
:on-success="handleUploadSuccess"
:on-error="handleUploadError"
:show-file-list="false"
:disabled="uploadPercent > 0 && uploadPercent < 100"
accept="video/*"
>
<el-button size="small" type="primary">{{
uploadPercent === 0
? '点击上传'
: uploadPercent === 100
? '重新上传'
: '视频上传中,请稍候...'
}}</el-button>
<div slot="tip" class="el-upload__tip">
支持所有视频文件,且不超过1GB
</div>
</el-upload>
视频上传进度条el-progress:
<el-progress
v-if="showPro"
v-show="uploadPercent > 0"
:percentage="uploadPercent"
:color="customColorMethod"
></el-progress>
视频上传完成后显示的视频地址(可复制):
<el-form-item v-if="uploadPercent === 100">
<span style="font-size:12px;font-weight:500">视频地址 : </span>
<el-link
id="videoLink"
:data-clipboard-text="'阿里云oss地址' + extraData.key"
type="info"
@click="
() => {
this.$message.success('复制视频地址成功')
}
"
>{{ '阿里云oss地址' + extraData.key
}}<i class="el-icon-document-copy el-icon--right"></i>
</el-link>
</el-form-item>
效果如下:
二、代码详解
1、el-upload组件
1)上传的地址 :action="ossParams.host || ''"
主要是获取上传阿里云的加密策略policy和签名signature,以及上传自己要上传到阿里云的地址,当然还有自己阿里云accessid。
2)上传时附带的额外参数:data="extraData"
参数如下:
extraData: {
key: '',
policy: '',
OSSAccessKeyId: '',
success_action_status: '200', //让服务端返回200,不然,默认会返回204
callback: '',
signature: ''
}
3)上传前通过:before-upload="beforeUpload"进行校验:
beforeUpload(file) {
if (file.size > 1024 * 1024 * 1024) {
this.$message.error('上传视频大小不能超过1G')
return false
}
const expire = this.ossParams.expire * 1000
if (expire < Date.now() - 1000 * 60) {
this.$message.error('token有效期已过期,请刷新页面重试')
return false
}
this.uploadPercent = 0
try {
const { policy, accessid, dir, callback, signature } = this.ossParams
const md5 = crypto.createHash('md5')
const nameHash = md5
.update(file.name.split('.')[0] + new Date().getTime().toString())
.digest('hex')
this.extraData.key = dir + nameHash + get_suffix(file.name)
this.extraData.policy = policy
this.extraData.OSSAccessKeyId = accessid
this.extraData.callback = callback
this.extraData.signature = signature
return true
} catch (err) {
console.log(err)
this.$message.error(err.message)
return false
}
},
4)上传时:on-progress="handleUploadProgress"
handleUploadProgress(event) {
this.uploadPercent = parseInt(event.percent)
},
5)上传成功 :on-success="handleUploadSuccess"
handleUploadSuccess(response, file, fileList) {
this.$message.success('视频上传成功')
this.$nextTick(() => {
const clipboard = new ClipboardJS('#videoLink')
})
console.log(response, file, fileList)
this.uploadPercent === 100
? (this.showPro = false)
: (this.showPro = true)
},
6)上传失败 :on-error="handleUploadError"
handleUploadError(err) {
this.$message.error('视频上传失败 ' + err.toString())
this.uploadPercent = 0
},
2、el-progress组件
1)进度条百分比动态变色:color="customColorMethod"
customColorMethod(percentage) {
if (percentage < 30) {
return '#909399'
} else if (percentage < 70) {
return '#e6a23c'
} else {
return '#67c23a'
}
}