一 . 背景 :
最近后台管理系统需要增加一个功能 - 上传视频, 但这个上传视频区别于上传到服务端, 需要前端上传到阿里云视频点播, 需要通过阿里云客户端sdk上传。
二 . 阿里云js sdk上传视频vod
官网文档 : https://www.alibabacloud.com/help/zh/apsaravideo-for-vod/latest/use-the-upload-sdk-for-javascript
文档里提供了两个上传方式 , 可以根据业务需求选择用上传地址和凭证方式或STS方式, 我们选用的是服务端给前端返回上传地址和凭证的方式。
三 . 实现 :
前提 :需要获取上传授权, 获取上传地址和凭证,需要后端接入,此处着重说明前端实现,不赘述服务端实现,总之叫后端给个接口获取这俩东西就好啦~
1. 引入JavaScript上传SDK
// 方式一 : 在HTML中通过script引用
<!-- IE需要es6-promise,目前支持IE 10及以上 -->
<script src="../lib/es6-promise.min.js"></script>
<script src="../lib/aliyun-oss-sdk-6.17.1.min.js"></script>
<script src="../aliyun-vod-upload-sdk-1.5.5.min.js"></script>
// 方式二 : 模块化引用
import OSS from '../lib/aliyun-upload-sdk/lib/aliyun-oss-sdk-6.17.1.min'
window.OSS = OSS;
import '../lib/aliyun-upload-sdk/aliyun-upload-sdk-1.5.5.min'
2. 声明初始化回调
var uploader = new AliyunUpload.Vod({
//userID,必填,您可以使用阿里云账号访问账号中心(https://account.console.aliyun.com/),即可查看账号ID
userId:"122",
//上传到视频点播的地域,默认值为'cn-shanghai',
//eu-central-1,ap-southeast-1
region:"",
//分片大小默认1 MB,不能小于100 KB(100*1024)
partSize: 1048576,
//并行上传分片个数,默认5
parallel: 5,
//网络原因失败时,重新上传次数,默认为3
retryCount: 3,
//网络原因失败时,重新上传间隔时间,默认为2秒
retryDuration: 2,
// 添加文件成功
addFileSuccess: function() {
console.log('添加文件成功')
// 添加文件成功后调起开始上传
uploader.startUpload()
},
//开始上传
'onUploadstarted': function (uploadInfo) {
// 上传方式,需要根据uploadInfo.videoId是否有值(该值由SDK通过localstorage获取),调用 视频点播的不同接口获取uploadauth和uploadAddress
// 如果videoId有值,调用刷新音视频上传凭证接口,否则调用获取音视频上传地址和凭证接口
// 上传过程中,如果在点播控制台删除了音频或视频,即videoId不存在了,则会产生冲突,会出现控制台不存在videoId,而浏览器存在videoId的情况,报InvalidVideo.NotFound错误。此时,需手动清除localstorage
var url = '';
if (uploadInfo.videoId) {
//如果uploadInfo.videoId存在,调用刷新音视频上传凭证接口
url = 'refreshUrl'; // 此处URL需要替换为服务端AppServer对应的地址
}
else{
//如果uploadInfo.videoId不存在,调用获取音视频上传地址和凭证接口
url = 'createUrl'; // 此处URL需要替换为服务端AppServer对应的地址
}
// 以下请求实现为示例,用于演示设置凭证
fetch(url)
.then((res) => res.json())
.then((data) => {
uploader.setUploadAuthAndAddress(uploadInfo, data.UploadAuth, data.UploadAddress, data.VideoId);
});
},
//文件上传成功
'onUploadSucceed': function (uploadInfo) {
//uploadInfo 包含要上传的文件信息
// {
// videoId: '', // videoId,由服务端返回的音/视频ID
// Endpoint: '', // OSS对外服务的访问域名
// Bucket: '', // OSS存储空间
// Object: '' // OSS存储数据的基本单元
// }
console.log(uploadInfo) // 此处可以获取到上传后的vod
},
//文件上传失败
'onUploadFailed': function (uploadInfo, code, message) {
},
//文件上传进度,单位:字节
'onUploadProgress': function (uploadInfo, totalSize, loadedPercent) {
},
//上传凭证或STS token超时
'onUploadTokenExpired': function (uploadInfo) {
//实现时,根据uploadInfo.videoId调用刷新音视频上传凭证接口重新获取UploadAuth
//从点播服务刷新的uploadAuth,设置到SDK里
var url = 'refreshUrl'; // 此处URL需要替换为服务端AppServer对应的地址
// 以下请求实现为示例,用于演示设置凭证
// 获取UploadAuth, UploadAddress, VideoId可能因AppServer实现有差异
fetch(url)
.then((res) => res.json())
.then((data) => {
uploader.resumeUploadWithAuth(data.UploadAuth);
});
},
//全部文件上传结束
'onUploadEnd':function(uploadInfo){
}
});
说明 :
1)由于我后台系统是使用antd pro 写的, 逻辑代码写在model.js , 若按如上文档demo在onUploadstarted等钩子里再请求凭证和地址, 因为写在effects异步函数, 在钩子里使用yield关键字进行异步请求, 会报错不能使用关键字, 所以我在项目中是先请求获取凭证和地址, 再进行初始化实例及调用, 目前可正常上传, 但是如果出现demo里提到的上传凭证超时或者其他需要区分刷新和获取凭证的情况时, 这样做是不满足的。
2)文档前提条件提到建议使用标准input方式选择文件,我项目里使用的是**ant design 的< Upload />**上传组件, 尝试过使用input, 但onchange事件获取不到file对象(onUploadstarted钩子需要传file对象), 遂放弃
3. 将选中的文件添加到上传列表中及开始上传
uploader.addFile(file,null,null,null,'{"Vod":{}}');
四 . 遇到的问题 :
1. 报错 - Illegal invocation
过程中遇到最大的坑莫过于这个了, 在addFile时, 弹出toast报"非法调用", 并且控制台无任何报错, 一番排查后发现addFile时的file对象错误, 晕死~
因为在上传视频后, 我的file对象经过一番处理, 把< Upload /> 上传后的file对象封装进了另一个对象里, 而进行vod上传时, addFile()添加的是我处理过后的file对象, 我需要传的是原始获取的file对象, 这就导致了一个很隐秘的非法调用的报错
2. 回写视频url到文件上传组件
因为上传到vod后, 此时我能够获取到的只有videoId, 而上传视频组件的列表里, 有个点击"视频"打开视频的功能, 这就需要通过这个vod再次请求服务端返回视频url来支持打开视频了。
这里涉及到视频上传组件的逻辑, 准备另外写一篇来说明实现方法。因为这里需要反向操作,反写fileList渲染列表。
五. 上传成功效果
六. 写在最后
此处只做了最简单的vod上传, 文档里超时等场景及其他高级应用都没有涉猎到, so 遇到问题看文档吧~ 对了, 实在解决不了还可以给阿里云提工单寻找帮助哦~