上傳視頻到亞馬遜平臺(S3,VUE Demo)

  *
    * 上傳亞馬遜的基本思路爲
    * ***
    * 1.調用後端接口,獲取需要上傳到亞馬遜的數據(從後臺獲取亞馬遜需要的數據)
    * 2.提交數據到亞馬遜之後,亞馬遜會自動刷新當前form表單的頁面,刷新後 將form表單所在頁面的url改變,將我們需要的字段通過url返回給我們
    * (後臺通過這些字段可以找到當前上傳視頻所在亞馬遜的位置及視頻信息)
    * 3.獲取到url中的信息後 將獲取信息通過接口發送給後端 完成上傳
    *
    * 因此需要注意的是:
    * 1.使用form表單提交(不然會有跨域問題)
    * 2.使用iframe包裹表單上傳(上傳成功後會刷新頁面我們不能讓我們操作的頁面刷新,只能通過iframe),
    * 3.同步上傳多個視頻就要同時生成多少個iframe,因爲每一個上傳都會有不同的返回值,想要獲取對應數據 就不能動當前上傳的iframe
    * (再次操作正在上傳的iframe會讓上傳停止)

 ******按照我下面所做可以解決網上說的跨域問題

1.主上傳頁面:

<template>
  <!--創建EXT跟grid配對的按鈕-->
  <el-dialog
    :title="$t('lang.addvideo')"
    :visible.sync="data.show"
    width="700px"
    :center="true"
    :close-on-click-modal="false"
    class="add-source-dialog"
    @close="cancel"
    :destroy-on-close="true"
  >
    <div class="content scrollbar">

      <el-row>
        <el-col :span="8" v-for="item in videoList" :key="item.id">
          <div class="videoList"
               v-loading="item.loading"
               :element-loading-text="$t('lang.proccessing')"
               element-loading-spinner="el-icon-loading"
               element-loading-background="rgba(40,71,48, 1)"
               v-if="!item.iframe"
          >
            <div class="waitThumbneil">
              <i class="iconfont videoWait">&#xe6d6;</i>
              <div class="delete">
                <i class="iconfont" @click="cancelUploadedVideo('deleteOne',item)"
                   :title="$t('lang.delete')">&#xe605;</i>
              </div>
              <div class="timeInfo" v-if="item.time && item.time != ''">
                {{item.time}}
              </div>
            </div>
            <div class="videoName ellipsis" @click="showEditName(item)">
              <span v-if='!item.editName'>{{item.fileName}}</span>
              <el-input
                v-model="item.fileName"
                v-if='item.editName'
                class="editName"
                :id="item.id"
                @change="editName"
                @blur="editName"
              ></el-input>
            </div>
          </div>
        </el-col>

        <el-col :span="8">
          <div class="uploadP">
            <i class="el-icon-plus avatar-uploader-icon"></i>
            {{$t('lang.upload')}}
            <uploadIframe @getUploadInfo="getUploadInfo"
                          :data="item"
                          :session="session"
                          :class="{opcaty:!item.show}"
                          v-for="item in iframe"
                          :key="item.id"
            ></uploadIframe>
          </div>

        </el-col>
      </el-row>
    </div>
    <span slot="footer" class="dialog-footer">
            <el-button class="save" @click.stop="save">{{$t('lang.add')}}</el-button>
            <el-button class="cancel" @click="cancelUploadedVideo('deleteAll')">{{$t('lang.cancel')}}</el-button>
    </span>

  </el-dialog>

</template>
<script>
    import 'vuex';
    import uploadIframe from './uploadIframe'

    export default {
        props: {
            data: Object,
            edit: Boolean,
            editData: Object,
            session: String
        },
        components: {
            uploadIframe,
        },
        data() {
            return {
                loading: true,
                videoList: [],
                iframe: [
                    {
                        id: Math.random(),
                        show: true,
                        session: session
                    },
                ],
            }
        },
        mounted() {

        },
        created() {
        },
        methods: {
            getUploadInfo(data) {
                // console.log(data);
                if (data.type == 'loadingStart') {
                    let addVideoObj = data.videoObj
                    let isHaveSameVideo = false; //是否上傳了 相同的video文件
                    this.videoList.map((item) => {
                        if (addVideoObj.id == item.id) {
                            isHaveSameVideo = true;
                        }
                    });
                    if (!isHaveSameVideo) {
                        this.videoList.push(addVideoObj);
                        this.videoList = Object.assign([], this.videoList);
                        this.iframe.map((item) => {
                            item.show = false;
                        })
                        this.iframe.unshift({
                            show: true,
                            id: Math.random(),
                            session: session
                        })
                    } else {
                        this.$message({
                            type: 'warning',
                            message: this.$t('lang.uploadHasSame')
                        })
                    }
                } else if (data.type == 'loadingEnd') {
                    let updateVideo = [];
                    this.videoList.map((item) => {
                        if (item.id == data.videoObj.id) {
                            item.loading = false;
                        }
                        updateVideo.push(item);
                    })
                    this.videoList = [];
                    this.videoList = Object.assign([], updateVideo);
                } else if (data.type == 'hasGetVideoTime') {
                    let videoTime = data.videoTime;
                    let md5 = data.md5;
                    this.showTimeInfo(md5, videoTime);
                } else {
                    this.$message({
                        type: 'warning',
                        message: this.$t('lang.failed')
                    })
                }
            },
            showTimeInfo(id, time) {//獲取到時間的時候將時間賦值給對應的vue數據 id => 對應的md5  time 對應的視屏時長
                let videoData = [];
                this.videoList.map((item) => {
                    if (item.id == id) { //文件一樣
                        item.time = time;
                    }
                })
            },
            showEditName(data) {
                let update = [];
                let currentId = data.id;
                this.videoList.map((item) => {
                    if (item.id == data.id) {
                        item.editName = true;
                    }
                    update.push(item);
                });
                this.videoList = Object.assign([], update);
                this.$nextTick(() => {
                    $("#" + currentId).focus();
                })
            },
            editName() {
                let update = [];
                this.videoList.map((item) => {
                    item.editName = false;
                    update.push(item);
                })
                this.videoList = Object.assign([], update);
            },
            cancelUploadedVideo(type, data) {
                /*
                * type:"是什麼操作 1.刪除一個 2.點擊X號 或者cancel按鈕"
                * */
                let Url = '';
                // let Url = '/event/editVideo';
                let params = [];
                if (type == 'deleteOne') {
                    let param = {
                        "fileName": data.fileName,
                        "md5Id": data.id,
                        "operationType": "del"
                    };
                    params.push(param);
                } else if (type == 'deleteAll') {
                    this.videoList.map((item) => {
                        let param = {
                            "fileName": item.fileName,
                            "md5Id": item.id,
                            "operationType": "del"
                        }
                        params.push(param);
                    });
              
                } else if (type == 'addAll') {
                    this.videoList.map((item) => {
                        let param = {
                            "fileName": item.fileName,
                            "md5Id": item.id,
                            "operationType": "add"
                        }
                        params.push(param);
                    })
                }
                if (params.length == 0) { //添加的時候 沒選擇視頻文件
                    if (type == 'addAll') {
                        this.$message({
                            type: 'warning',
                            message: this.$t('lang.selectAVideo')
                        })
                        return false;
                    } else if (type == 'deleteAll') { //取消全部
                        this.clear();
                        return false;
                    }
                }
                this.axios.post(Url, params, {contentType: 'application/json;charset=UTF-8'}).then(res => {
                    if (res.data.errorCode == '0x0') {
                        if (type == 'deleteOne') {
                            this.videoList.map((item, index) => { //刪除當前刪除的視屏
                                if (data.id == item.id) {
                                    this.videoList.splice(index, 1);
                                }
                            })
                        } else { //cancel和add操作 關閉彈窗
                            this.clear();
                            if (type == 'addAll') {
                                this.$emit('queryList');
                                this.$message({
                                    type: 'success',
                                    message: this.$t('lang.success')
                                })
                            }
                        }
                    } else if (res.data.errorCode == '80600700') {
                        this.$message({
                            type: 'warning',
                            message: this.$t('lang.serverFailed')
                        })
                    }
                })
            },
            save() {
                this.cancelUploadedVideo('addAll');
               // bookingAnalyze(`bookingVideoAdd`, '/bk');
            },
            cancel() {
                // this.cancelUploadedVideo('deleteAll');
                this.clear();
                this.data.show = false;
                //bookingAnalyze(`bookingVideoCancel`, '/bk');
            },
            clear() {
                this.data.show = false;
                this.videoList = [];
                this.iframe = [
                    {
                        id: Math.random(),
                        show: true,
                        session: session
                    },
                ]
            }
        }

    }
</script>
<style lang="less" scoped>
  .opcaty {
    opacity: 0 !important;
    width: 0 !important;
    height: 0 !important;

  }

  /deep/ .el-upload__input {
    display: none;
  }

  .videoList {
    width: 90%;
    height: 140px;
    margin: 20px auto;

    .editName {
      height: 30px;
      width: 100%;

      /deep/ .el-input__inner {
        width: 100% !important;
        height: 30px !important;
        background: #333333 !important;
        border: none !important;
      }
    }

    .waitThumbneil:hover .delete {
      display: block;
    }

    .waitThumbneil {
      height: 106px;
      line-height: 106px;
      text-align: center;
      background: rgba(44, 44, 44, 1);
      position: relative;
      font-size: 24px;
      color: #318F47;

      i {
        cursor: pointer;
      }

      .delete {
        position: absolute;
        left: 0;
        bottom: 0;
        width: 100%;
        height: 30px;
        line-height: 30px;
        text-align: center;
        font-size: 16px;
        color: white;
        background: rgba(2, 0, 3, .1);
        display: none;
        z-index: 2;

        i {
          cursor: pointer;
        }
      }

      .timeInfo {
        position: absolute;
        left: 0;
        bottom: 0;
        width: 100%;
        height: 30px;
        line-height: 30px;
        text-align: right;
        color: white;
        font-size: .12rem;
        padding: 0 10px;
        z-index: 1;
      }
    }

    .videoName {
      height: 30px;
      line-height: 30px;
      text-align: center;
      width: 100%;
      padding: 0 10px;
      color: #6B6B6B;
      background: #333333;
      margin-top: 4px;
    }
  }

  .uploadP {
    width: 100%;
    height: 140px;
    margin: 20px auto;
    border: 1px dashed #3A3A3A;
    line-height: 140px;
    position: relative;
    text-align: center;

    #iframe {
      position: absolute;
      top: 0;
      left: 0;
      opacity: 0;
      width: 182px;
      height: 140px;
      cursor: pointer;
    }
  }

  .add-source-dialog {
    .scrollbar {
      overflow-x: hidden;
    }

    .content {
      text-align: left;
      font-size: 16px;
      height: 200px;
      max-height: 55vh;
      overflow-y: auto;

      .item {
        margin-bottom: 10px;

        &:last-child {
          margin-bottom: 0;
        }

        span {
          display: block;
          margin-bottom: 5px;
        }
      }

      /deep/ .el-input .el-input__inner {
        border: 1px solid #444;
        background: #444;
        height: 46px;
        line-height: 46px;
        color: white !important;

        &::-webkit-input-placeholder {
          color: #666;
        }
      }

      /deep/ .select-box {
        width: 100%;

        .el-input__inner {
          border: 1px solid #444;
          background: #444;
          height: 46px;
          line-height: 46px;

        }
      }

      /deep/ .el-select {
        width: 100%;

        .el-select__input {
          color: #fff;
        }
      }

      /deep/ .selectRlist {
        width: 100%;
        height: 300px;
        overflow-y: auto;
      }
    }
  }

  .delete {
    width: 120px;
  }
</style>

2.Iframe頁面

 

<template>
  <iframe id="iframe" frameborder=0 scrolling=auto width="100%" height="100%" :src="iframeUrl"
          :session="cusession"></iframe>
</template>

<script>
    import {bookingAnalyze} from '@/assets/js/googleAnalyze/booking.js'

    export default {
        data() {
            return {
                cusession: this.session,
                iframeUrl: '',
                currentData: this.item,
            }
        },
        props: ['data', 'session'],
        created() {
            let protocol = document.location.protocol;
            let seession = this.session;
            // this.iframeUrl = `${protocol}//${localStorage.getItem('newCCUrl')}/uploadVideo.html#?session=${seession}`; //線上使用
            this.iframeUrl = window.location.origin + '/uploadVideo.html#/?session=' + this.session;
            let _this = this;
            window.uploadVideo = (data) => {  //獲取上傳的成功失敗信息
                if (data.type == 'loadingStart') {
                    let videoObj = {
                        fileName: data.msg.fileName,
                        loading: true,
                        id: data.msg.id,
                        editName: false,
                        time: '',
                    };
                    let msg = {
                        type: 'loadingStart',
                        videoObj: videoObj
                    }

                    _this.$emit('getUploadInfo', msg);
                    // this.$message({
                    //     type: 'warning',
                    //     message: this.$t('lang.uploadHasSame')
                    // })
                } else if (data.type == 'loadingEnd') {
                    let videoObj = {
                        id: data.msg.id,
                    };
                    let msg = {
                        type: 'loadingEnd',
                        videoObj: videoObj
                    }
                    _this.$emit('getUploadInfo', msg);
                } else if (data.type == 'hasGetVideoTime') {//獲取到當前視頻的時長
                    let timeInfo = data.msg;
                    timeInfo.type = 'hasGetVideoTime';
                    _this.$emit('getUploadInfo', timeInfo);
                } else if (data.type == 'alertErrorCode') {
                    if(data.msg == '80601804'){
                        _this.$message({
                            type: 'warning',
                            message: this.$t('lang.videoExist')
                        })
                    }else{
                        _this.$message({
                            type: 'warning',
                            message: this.$t('lang.failed')
                        })
                    }

                }
            }
            window.getSessionIframe = () => {
                // console.log(111,this.$store.state.common); //所有的initConfig信息
                let videoInfo = {};
                return this.session;
            }
        },
    }
</script>

<style scoped>
  .uploadP {
    width: 100%;
    height: 140px;
    margin: 20px auto;
    border: 1px dashed #3A3A3A;
    line-height: 140px;
    position: relative;
    text-align: center;
  }

  #iframe {
    position: absolute;
    top: 0;
    left: 0;
    opacity: 0;
    width: 182px;
    height: 140px;
    cursor: pointer;
  }

</style>

 

3.鑲嵌在iframe內的form表單

<template>
  <div class="button">
    <form class="form-horizontal" id="formUpload" :action="formdata.uploadUrl" method="post"
          enctype="multipart/form-data">
      <input type="hidden" name="acl" :value="formdata.acl"/>
      <input type="hidden" name="key" :value="formdata.objectKey"/>
      <input type="hidden" name="policy" :value="formdata.policy"/>
      <input type="hidden" name="success_action_redirect" :value="href"/>
      <input type="hidden" name="success_action_status" value="200"/>
      <input type="hidden" name="x-amz-algorithm" :value="formdata.algorithm"/>
      <input type="hidden" name="x-amz-credential" :value="formdata.credential"/>
      <input type="hidden" name="x-amz-date" :value="formdata.date"/>
      <input type="hidden" name="x-amz-signature" :value="formdata.signature"/>
      <!--      <input type="hidden" name="x-amz-meta-programId" :value="programId"/>-->
      <!--      <input type="hidden" name="x-amz-meta-name" :value="fileName"/>-->
      <label for="videoUpload" class="videoUpload">
        <input type="file" name="file" :accept="accept" @change="handlePrepareUpload($event)" class="videoUpload"
               id="videoUpload"/>
      </label>
      <button id="uploadFile" type="submit"></button>
    </form>

    <video :src="videoUrl" id="file"></video>
  </div>
</template>

<script>
    import {requestUpload, notifyUploadVideoSuccess} from '@/assets/js/uploadApi';
    import SparkMD5 from 'spark-md5';
    import Outil from '@/assets/js/utils.js'

    const url = require("url");
    export default {
        created() {
            const href = window.location.href;
            let programId = '1000';
            const urlPaseObj = url.parse(href, true).query;
            const urlOwnSend = url.parse(href, true).hash;//自己傳遞的參數
            // if(urlPaseObj.hasOwnProperty("programId")){
            //     this.programId = urlPaseObj.programId;
            // }
            if (urlPaseObj.hasOwnProperty("region")) {
                this.region = urlPaseObj.region;
            }
            if (urlPaseObj.hasOwnProperty("bucket")) {
                let videoUplodInfo = JSON.parse(window.localStorage.getItem('uploadVideo'));
                let md5 = Outil.getQueryString('md5', urlOwnSend);
                let bucketSend = Outil.getQueryString('bucketSend', urlOwnSend);
                let region = Outil.getQueryString('region', urlOwnSend);
                let fileName = Outil.getQueryString('fileName', urlOwnSend);
                let session = Outil.getQueryString('session', urlOwnSend);
                const params = {
                    bucket: urlPaseObj.bucket,
                    key: urlPaseObj.key,
                    fileMD5Id: md5,
                    region: region,
                    nickName: fileName,
                    url: urlPaseObj.key,
                    session: session
                }
                let fileInfo = {
                    id: md5, //每一個file都有一個不一樣的md5 相同文件有相同的md5 (可以用於相同文件上傳的去重操作)
                }
                parent.uploadVideo({type: 'loadingEnd', msg: fileInfo});
                this.notifyUploadSuccess(params);
            }
            this.href = location.href;
        },
        data() {
            return {
                programId: '1000',
                fileName: '',
                region: '',
                href: '',
                accept: '.ts,.rm,.rmvb,.wmv,.wtv,.avi,.3gp,.mkv,.mpg,video/mpeg,video/mp4,.mov',
                formdata: {
                    acl: "",
                    algorithm: "",
                    bucket: "",
                    credential: "",
                    date: "",
                    objectKey: "",
                    policy: '',
                    region: "",
                    signature: "",
                    uploadUrl: "",
                },
                videoUrl: '',
            }
        },
        methods: {
            async inputValue(event, md5) { // 觸發onchange 事件之後,需要獲取文件名,等信息,和java獲取上傳的一下信息,填入文件之後,自動觸發上傳事件上傳文件
                // 獲取名字
                const pathArr = event.target.value.split('\\');
                const names = pathArr[pathArr.length - 1].split(".");
                const idx = pathArr[pathArr.length - 1].lastIndexOf('.');
                const sourceName = pathArr[pathArr.length - 1].substring(0, idx);
                this.fileName = sourceName;
                let suffix = names[names.length - 1];
                // 遍歷數據
                const arr = this.accept.split(',').filter(item => {
                    if (item.indexOf(suffix) > -1) {
                        return item;
                    }
                });
                if (arr.length == 0) {
                    // parent.uploadVideo({type: 'error', msg: 'file type error'});
                    event.target.value = '';
                    return false;
                }

                const params = { //bucket和region需要向亞馬遜平臺申請
                    "fileName": pathArr[pathArr.length - 1],
                    "bucket": "",
                    "region": "",
                    fileMD5Id: md5,
                }
                const res = await requestUpload(params);
                // return false;
                if (res.data.errorCode === "0x0") {
                    let protocol = document.location.protocol;
                    let seession = parent.getSessionIframe();
                    this.href = window.location.origin + '/uploadVideo.html#/?session=' + parent.getSessionIframe() + '&md5=' + md5 + '&region=ap-northeast-2' + "&bucketSend=pp-kr-001" + '&fileName=' + pathArr[pathArr.length - 1] + '&session=' + parent.getSessionIframe();  //本地test使用
                    let sendObj = {
                        md5: md5,
                        region: '',
                        bucketSend: '',
                        fileName: pathArr[pathArr.length - 1],
                    };
                    const result = res.data.result;
                    this.formdata = result;
                    this.$nextTick(() => {
                        document.getElementById("uploadFile").click();
                        let fileInfo = {
                            fileName: pathArr[pathArr.length - 1],
                            id: md5, //每一個file都有一個不一樣的md5 相同文件有相同的md5 (可以用於相同文件上傳的去重操作)
                        }
                        parent.uploadVideo({type: 'loadingStart', msg: fileInfo});
                    })
                } else {
                    if (res.data.errorCode) {
                        parent.uploadVideo({type: 'alertErrorCode', msg: res.data.errorCode});
                    }
                    event.target.value = '';
                }
            },
            async notifyUploadSuccess(params) { // 上傳成功,s3回調之後,通知java去修改狀態
                const res = await notifyUploadVideoSuccess(params);
                if (res.data.errorCode !== '0x0' && res.data.errorCode != '80601804') {
                    setTimeout(() => {
                        this.notifyUploadSuccess(params);
                    }, 1000);
                }
            },

            handlePrepareUpload(event) { // 文件上傳獲取md5值
                var fileReader = new FileReader();
                //文件讀取完畢之後的處理
                fileReader.onload = function (e) {
                    spark.appendBinary(e.target.result);
                    var md5 = spark.end();
                    _this.inputValue(event, md5);
                    // _this.getMd5Checked(md5)
                    let video = document.getElementById('file');
                    let inputFile = document.getElementById('videoUpload').files[0];
                    let url = URL.createObjectURL(inputFile);
                    console.log(url);
                    video.src = url;
                    setTimeout(() => {
                        //獲取時長方式: 將獲取的本地地址給video去播放 然後獲取video的屬性 獲取時長,但是賦值給video的時候不會在瞬間獲取到視頻信息 因此需要延遲1s左右的時間
                        if (video.readyState > 0) {
                            let videoTime = Outil.MillisecondToDate(video.duration);
                            let timeInfo = {
                                videoTime: videoTime,
                                md5: md5,
                            }
                            parent.uploadVideo({type: 'hasGetVideoTime', msg: timeInfo});
                        }
                    }, 1000)
                };
                var dataFile = event.srcElement.files[0];

                const _this = this
                var spark = new SparkMD5(); //創建md5對象(基於SparkMD5)
                if (dataFile.size > 1024 * 1024 * 10) {
                    var data1 = dataFile.slice(0, 1024 * 1024 * 10); //將文件進行分塊 file.slice(start,length)
                    fileReader.readAsBinaryString(data1); //將文件讀取爲二進制碼
                } else {
                    fileReader.readAsBinaryString(dataFile);
                }
            },
        },
        mounted() {
            const formUpload = document.getElementById("formUpload");
            formUpload.onsubmit = (event) => {
                // 觸發父頁面的加載狀態
                parent.uploadVideo({type: 'loadingPage'});
                return true;
            };

        },
    }
</script>

<style lang="less">
  * {
    margin: 0;
    padding: 0;
  }

  html, body {
    width: 182px;
    height: 140px;
    display: block;
  }

  #file {
    width: 0;
    height: 0;
    opacity: 1;
  }

  .button {
    width: 182px;
    height: 140px;

    button {
      display: none;
    }

    .videoUpload {
      width: 182px;
      height: 140px;
      opacity: 0;
      cursor: pointer;
      display: block;
    }

    #videoUpload {
      display: none;
    }
  }
</style>

4.請求後臺接口js(根據實際情況修改)

import Axios from 'axios';
import Tool from '@/assets/js/utils.js';

const session = Tool.getSession();

// example
export async function requestUpload(params) {
  // axios.defaults.headers.authorization = token;
  let url = '';
  const res = await Axios.post(url, params,{contentType: 'application/json;charset=UTF-8'});
  return res;
}

export async function notifyUploadVideoSuccess(params) {
  let url = '';
  const res = await Axios.post(url, params,{contentType: 'application/json;charset=UTF-8'});
  return res;
}

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章