微信小程序直传视频到阿里云视频点播

  • 爵特猛
  • 2020-3-25 09:43
  • PHP
  • 929

需求:在小程序上传视频,直传给阿里云视频点播。

爵特猛

爵特猛

爵特猛


阿里云给的文档太过简单,踩了不少的坑。在网上搜了不少教程也是不太详细。现在记录一下,以免日后踩同样的坑。

 

网上其他教程和阿里云的文档大多都是在小程序端进行解析上传凭证再进行加密,会将accessKeyIdaccessKeySecret暴露在前端,不安全。本文将所有解析加密过程写在后端,后端处理好后,直接返回前端需要的数据,然后进行上传。

 

简单理一下上传视频的整个流程:

选择视频(前端)→获取视频上传凭证(后端)→解析上传凭证组装成前端需要的格式(后端)→根据后端返回的数据上传视频(前端)

 

详细步骤:

 

一、小程序前端js代码:

 

1.       调用wx.chooseVideo拍摄或从手机相册选中需要上传的视频。参考:wx.chooseVideo文档

 

    小程序js代码:

//选取视频
chooseVideo: function () {
  var that = this;
  wx.chooseVideo({
    sourceType: ['album', 'camera'],
    maxDuration: 60,
    camera: 'back',
    success: function (res) {
      //这里取整,避免一些视频时长是在60-61之间的情况下无法上传
      var duration = parseInt(res.duration);
      if (duration > 60) {
        app.tips('视频时长不可超过' + 60 + '秒');
        return false;
      } else {
        var file_arr = res.tempFilePath.split('.');
        var file_suffix = file_arr[file_arr.length - 1];//视频后缀
 
        //屏幕宽度,单位rpx
        var widow_width_rpx = Math.round(wx.getSystemInfoSync().windowWidth * (750 / wx.getSystemInfoSync().windowWidth));
        //视频容器高度,单位rpx
        var video_height = widow_width_rpx * 9 / 16;
 
        that.setData({
          video_tmp: res,//视频临时文件信息
          video_height: video_height,//视频预览框高度
          file_suffix: file_suffix,//视频后缀
        })
      }
 
    }
  })
}

 

 

2.       将视频后缀、视频标题传给后端,后端请求阿里云获取视频上传凭证。参考:阿里云视频上传凭证文档

 

    小程序js代码:

//获取视频上传凭证
getUploadAuth: function (){
  var that = this
 
  wx.showLoading({
    title: '加载中',
  })
  wx.request({
    url: app.https + '/api/Video/getUploadAuth',
    data: {
      file_suffix: that.data.file_suffix,
      file_title: that.data.file_title,
    },
    method: 'POST',
    header: {
      'content-type': 'application/x-www-form-urlencoded'
    },
    success: function (res) {
      wx.hideLoading()
      if(res.data.code==0){
        var data = res.data.data
        //上传视频
        that.uploadVideo(data)
      }else{
        console.log('获取凭证失败')
      }
    }
  })
}

 

 

3.       后端成功返回上次凭证后,调用wx.uploadFile进行视频上传。参考wx.uploadFile文档

 

注意

(大坑)上传到阿里云视频点播,使用的方式是STS上传,必须在formData里加上x-oss-security-token,不然会报403错误,提示OSSAccessKeyId无效。参考:OSS上传在Header中包含签名

爵特猛

 

    小程序js代码:

//上传视频
uploadVideo: function(data){
  var that = this
 
  var video_tmp = that.data.video_tmp;//本地视频文件信息
  var _upload = data.upload_auth;//后端返回的上传凭证信息
 
  wx.showLoading({
    title: '视频上传中',
  })
 
  const uploadTask = wx.uploadFile({
    url: _upload.host,//服务端返回的上传地址
    formData: {
      'key': _upload.key,//key是阿里云储存路径,也是服务端获取并提供的
      'policy': _upload.policy,//policy是经过Base64编码了的相关设置,也很重要,也是服务端获取并提供的
      'OSSAccessKeyId': _upload.access_key_id,//阿里云身份标识,也是服务端获取并提供的
      'signature': _upload.signature,//签名身份验证,也是服务端获取并提供的
      'x-oss-security-token': _upload.security_token,//因为是STS上传,必须加上security_token,不然会报403错误,一直说OSSAccessKeyId无效
    },
    name: 'file',
    filePath: video_tmp.tempFilePath,//上传文件的本地地址
    header: {
      'content-type': 'multipart/form-data;boundary=' + video_tmp.size,
      'file': video_tmp.tempFilePath,//上传文件的本地地址
      'key': _upload.key//阿里云存储路径
    },
    success: res => {
      wx.hideLoading()
      if(res.statusCode==204){
        console.log('视频上传成功');
      }
    }
  })
  //监听上传进度
  uploadTask.onProgressUpdate((res) => {
    // console.log('上传进度', res.progress)
    that.setData({
      upload_progress: res.progress,
    })
  })
}

 

小程序完毕。

 

 

二、后端获取视频上传凭证,并解析凭证后返回上传凭证信息给小程序。(后端语言:PHP

 

1.       首先根据前端传入的视频标题和后缀,组成文件名,根据项目的实际情况获取视频上传凭证,这里就不记录怎么获取凭证了,详情看文档。参考文档:获取视频上传凭证文档

 

2.       调用视频点播的接口获取到UploadAuthUploadAddress,将这两个字符串进行base64解析。使用base64解析UploadAuth字符串,可以得到json格式的上传凭证;使用base64解析UploadAddress字符串,可以得到json格式的上传地址。再将解析后的数据重新拼装,返回给小程序。

            PHP代码:

/**
 * 获取小程序上传视频需要的上传凭证
 * @param    string                   $title    视频标题
 * @param    string                   $filename 视频源文件名
 * @return   array                              组装好的上传凭证信息数组
 */
public function getUploadAuthByXcx($title,$filename)
{
    $AliVod = new Alivod();
    $vod_res = $AliVod->createUploadVideo($title,$filename);
    if($vod_res['Code']){
        return $this->setError(20004,'获取上传视频凭证失败');
    }else{
        //base解密再json转码后可获得上传授权密钥ID、上传授权密钥、上传授权安全令牌、上传授权过期时间,视频为3000秒,过期需要刷新上传凭证
        $upload_auth = json_decode(base64_decode($vod_res['UploadAuth']),true);
        //base解密再json转码后可获得OSS区域地址、OSSBucket名称、分配的媒体文件名
        $upload_address = json_decode(base64_decode($vod_res['UploadAddress']),true);
 
        //设置文件大小限制
        $max_size = 1024 * 1024 * 200;
        //设置凭证有效期,一个小时后过期
        $e_time = date('Y-m-d\TH:i:s\Z', time()+3600 - date('Z'));
        //组装成json格式的policy
        $_policy = "{\"expiration\": \"" . $e_time . "\",\"conditions\": [[\"content-length-range\", 0, " . $max_size . "]]}";
        //base64加密policy
        $policy = base64_encode($_policy);
 
        $upload['policy'] = $policy;
 
        //通过bucket名称和区域地址组装上传地址
        $upload['host'] = str_replace('https://','https://'.$upload_address['Bucket'].'.',$upload_address['Endpoint']);
        //分配到的文件名
        $upload['key'] = $upload_address['FileName'];
        //上传授权密钥ID
        $upload['access_key_id'] = $upload_auth['AccessKeyId'];
        //上传授权安全令牌
        $upload['security_token'] = $upload_auth['SecurityToken'];
        //根据policy和授权密钥加密生成签名
        $upload['signature'] = base64_encode(hash_hmac('sha1', $policy, $upload_auth['AccessKeySecret'], true));
 
        $upload['ali_vod_id']     = $vod_res['VideoId'];
        return $upload;
    }
}


本文为爵特猛原创文章,转载无需和我联系,但请注明来自爵特猛博客www.juetemeng.com