記錄一下前端分片上傳七牛雲踩過的坑

原由

  • 最近在工做中有個上傳大文件的需求,原先諮詢過組裏的大佬給我推薦了百度的webupload,但後來引入以後發現它是基於jquery封裝的。因爲自己項目是基於vue開發的因此與jquery相關的開源框架就儘可能不考慮了。
  • 後來查閱了資料後本身手動實現了文件切片上傳到服務器基本需求已經實現,但因爲效率及穩定性問題後來決定仍是直傳文件到七牛雲。一開始我使用了表單上傳的方式實現了,後來種種緣由又要求我作成分片上傳。。
  • 那我只好引入七牛的jssdk,因而走向了無盡的踩坑之路...

開擼

首先,剛接觸一門新的技術咱們仍是先去官方文檔走一圈瞭解下基本用法~
https://developer.qiniu.com/k...
通讀一遍以後我再來說講官網給咱們埋下了多少個坑。。。javascript

首先官網給咱們提供了三個相當重要的連接,嗯樓主好人一輩子平安。
前面兩個都是gayhub連接咱們能夠下載其sdk源碼在項目中引入。若是想預先體驗一下上傳能夠點擊第三個連接去官方demo玩一玩。
clipboard.pnghtml

後端返回給你的獲取token的json格式必須是這種格式的。必須是一個json對象內部包裹着uptoken字段,帶上其餘字段也是能夠的可是必須第一層要能找到uptoken前端

{
    "uptoken": "0MLvWPnyya1WtPnXFy9KLyGHyFPNdZceomL...",
    "xxx": "..."
    }

由於在它的sdk源碼中是這麼獲取token的。他會先找定義的option字段中是否有uptoken,若是沒有再去找uptoken_url有就發送ajax請求去獲取uptoken字段,假若後端必需要以他的格式爲主那你能夠修改sdk源碼來實現。若是uptoken_url也沒有值就回去調用uptoken_func函數都沒有則報錯,因此這三個必須指定一個.vue

// getUptoken maybe called at Init Event or BeforeUpload Event
        // case Init Event, the file param of getUptken will be set a null value
        // if op.uptoken has value, set uptoken with op.uptoken
        // else if op.uptoken_url has value, set uptoken from op.uptoken_url
        // else if op.uptoken_func has value, set uptoken by result of op.uptoken_func
        var getUpToken = function(file) {
            if (op.uptoken) {
                that.token = op.uptoken;
                return;
            } else if (op.uptoken_url) {
                logger.debug("get uptoken from: ", that.uptoken_url);
                // TODO: use mOxie
                var ajax = that.createAjax();
                ajax.open('GET', that.uptoken_url, false);
                ajax.setRequestHeader("If-Modified-Since", "0");
                // ajax.onreadystatechange = function() {
                //     if (ajax.readyState === 4 && ajax.status === 200) {
                //         var res = that.parseJSON(ajax.responseText);
                //         that.token = res.uptoken;
                //     }
                // };
                ajax.send();
                if (ajax.status === 200) {
                    var res = that.parseJSON(ajax.responseText);
                    that.token = res.uptoken;
                    logger.debug("get new uptoken: ", res.uptoken);
                } else {
                    logger.error("get uptoken error: ", ajax.responseText);
                }
                return;
            } else if (op.uptoken_func) {
                logger.debug("get uptoken from uptoken_func");
                that.token = op.uptoken_func(file);
                logger.debug("get new uptoken: ", that.token);
                return;
            } else {
                logger.error("one of [uptoken, uptoken_url, uptoken_func] settings in options is required!");
            }
        };

再往下看是這麼一段話
clipboard.png
我說你就短短1419行代碼還能分片上傳斷點續傳還兼容各大瀏覽器這不科學啊。原來是基於plupload插件之上封裝的。注意plupload已經更新到2.3.1了,而且2.2開始已經把moxie幹掉了而七牛雲的sdk是須要moxie的,因此若是你引入了2.2及其以上的版本會報這樣的錯誤html5

Uncaught ReferenceError: mOxie is not defined

此處奉上cdn地址java

<script src="https://cdn.staticfile.org/plupload/2.1.9/plupload.full.min.js"></script>

中間的版本號能夠更換成你想要的,可是建議你們直接訪問cdn地址copy下來用本地路徑訪問。
七牛sdk仍是支持npm引入形式的,你能夠經過npm安裝jquery

npm install qiniu-js

而後在項目中使用import引入git

import 'qiniu-js/dist/qiniu.min.js';

可是這樣不方便修改源代碼並且修改了源代碼以後下一我的接到你的項目從新npm install以後又會有各類坑。因此建議提取出來放到公共路徑經過script方式引入,不過我以爲能夠本身封裝一層經過import引入更好~web

通過上面兩個步驟咱們項目應該是這樣的:ajax

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>vue_test</title>
  </head>
  <body>
    <div id="app"></div>
    <!-- built files will be auto injected -->

    <!-- <script src="/static/moxie.js" charset="utf-8"></script>
    <script src="/static/plupload.dev.js" charset="utf-8"></script> -->
    <script src="/static/plupload.full.min.js" charset="utf-8"></script>
    <script src="/static/qiniu.js" charset="utf-8"></script>
  </body>
</html>

此處我是將文件提取到static目錄下面,用過vue-cli的應該知道~
這裏你能夠選擇引入plupload生產文件或者替換成上面兩種文件就是開發調試版本~

那麼如今咱們要開擼了~
首先,沒有什麼是一個div解決不了的,假若你還想實現拖拽上傳那就兩個。

<div id="container">
    <div id="pickfiles">上傳按鈕</div>
</div>

接下來咱們要編寫配置信息以及處理上傳的事件。在vue中咱們須要寫在mouted函數中。

var uploader = Qiniu.uploader({
      runtimes: 'html5,flash,html4',      // 上傳模式,依次退化(照着官網來就是了)
      browse_button: 'pickfiles',         // 上傳選擇的點選按鈕,必需(記得定義id而且保持一致)
      // 在初始化時,uptoken,uptoken_url,uptoken_func三個參數中必須有一個被設置
      // 切若是提供了多個,其優先級爲uptoken > uptoken_url > uptoken_func
      // 其中uptoken是直接提供上傳憑證,uptoken_url是提供了獲取上傳憑證的地址,若是須要定製獲取uptoken的過程則能夠設置uptoken_func
      uptoken : '<Your upload token>', // uptoken是上傳憑證,由其餘程序生成
      uptoken_url: '/uptoken',         // Ajax請求uptoken的Url,強烈建議設置(服務端提供)
      uptoken_func: function(){        // 在須要獲取uptoken時,該方法會被調用
         // do something(通常是發送手動發送ajax獲取到token,若是後端返回格式不跟官方一致又不想該懂源代碼能夠經過這個方式調整)
         return uptoken;
      },
      get_new_uptoken: false,             // 設置上傳文件的時候是否每次都從新獲取新的uptoken(沒有特殊需求通常爲false)
      // downtoken_url: '/downtoken',(未使用到,能夠不設置)
      // Ajax請求downToken的Url,私有空間時使用,JS-SDK將向該地址POST文件的key和domain,服務端返回的JSON必須包含url字段,url值爲該文件的下載地址
      // unique_names: true,              // 默認false,key爲文件名。若開啓該選項,JS-SDK會爲每一個文件自動生成key(文件名)
      // save_key: true,                  // 默認false。若在服務端生成uptoken的上傳策略中指定了sava_key,則開啓,SDK在前端將不對key進行任何處理
      domain: '<Your bucket domain>',     // bucket域名,下載資源時用到,必需(找後端拿)
      container: 'container',             // 上傳區域DOM ID,默認是browser_button的父元素(若是不實現拖拽上傳能夠不設置)
      max_file_size: '100mb',             // 最大文件體積限制(能夠調大)
      flash_swf_url: 'path/of/plupload/Moxie.swf',  //引入flash,相對路徑(若是沒用到flash上傳的話能夠不設置,通常支持html5上傳的瀏覽器都不會用到它)
      max_retries: 3,                     // 上傳失敗最大重試次數(自動幫你續傳分片)
      dragdrop: true,                     // 開啓可拖曳上傳(若是不實現拖拽上傳能夠不設置)
      drop_element: 'container',          // 拖曳上傳區域元素的ID,拖曳文件或文件夾後可觸發上傳(若是不實現拖拽上傳能夠不設置)
      chunk_size: '4mb',                  // 分塊上傳時,每塊的體積
      auto_start: true,                   // 選擇文件後自動上傳,若關閉須要本身綁定事件觸發上傳
      //x_vars : {                        // (未使用到,能夠不設置)
      //    查看自定義變量
      //    'time' : function(up,file) {
      //        var time = (new Date()).getTime();
                // do something with 'time'
      //        return time;
      //    },
      //    'size' : function(up,file) {
      //        var size = file.size;
                // do something with 'size'
      //        return size;
      //    }
      //},
      init: {
          'FilesAdded': function(up, files) {
              plupload.each(files, function(file) {
                  // 文件添加進隊列後,處理相關的事情
              });
          },
          'BeforeUpload': function(up, file) {
                 // 每一個文件上傳前,處理相關的事情
                 // (上傳文件前作一些處理)
          },
          'UploadProgress': function(up, file) {
                 // 每一個文件上傳時,處理相關的事情
                 // (能夠設置進度條信息)
          },
          'FileUploaded': function(up, file, info) {
                 // 每一個文件上傳成功後,處理相關的事情
                 // 其中info是文件上傳成功後,服務端返回的json,形式如:
                 // {
                 //    "hash": "Fh8xVqod2MQ1mocfI4S4KpRL6D98",
                 //    "key": "gogopher.jpg"
                 //  }
                 // 查看簡單反饋
                 // var domain = up.getOption('domain');
                 // var res = parseJSON(info);
                 // var sourceLink = domain +"/"+ res.key; 獲取上傳成功後的文件的Url
          },
          'Error': function(up, err, errTip) {
                 //上傳出錯時,處理相關的事情
          },
          'UploadComplete': function() {
                 //隊列文件處理完畢後,處理相關的事情
          },
          'Key': function(up, file) {
              // 若想在前端對每一個文件的key進行個性化處理,能夠配置該函數
              // 該配置必需要在unique_names: false,save_key: false時才生效

              var key = "";
              // do something with key here
              // (能夠自定義key不設定默認是文件名)
              return key
          }
      }
  });

  // domain爲七牛空間對應的域名,選擇某個空間後,可經過 空間設置->基本設置->域名設置 查看獲取

  // uploader爲一個plupload對象,繼承了全部plupload的方法

若是頁面中由多個上傳實例,那無非就是多建立幾個upload對象傳入指定參數設置~

總結

因爲本次項目中只涉及到大文件上傳,沒有圖像處理等相關的api使用經驗官方的案例就很少講了。總結起來七牛雲上傳的套路就是後臺爲你提供uptoken或者獲取uptoken的接口地址以後上傳的時候要帶上這個token。返回的字段最好是按照官方的格式來,若是不是的話也能夠修改源代碼或者在uptoken_func中手動獲取,另外若是要修改上傳的服務器也是要在qiniu.js中修改

/**
     * qiniu upload urls
     * 'qiniuUploadUrls' is used to change target when current url is not avaliable
     * @type {Array}
     */
    var qiniuUploadUrls = [
        // "http://upload.qiniu.com",
        // "http://up.qiniu.com",
        "修改爲你須要的地址",
    ];

若是使用表單上傳的話能夠不引用任何插件直接生擼上去。代碼實現以下:

html:
        <form id="testform" method="post" enctype="multipart/form-data">
            <input name="key" id="key" type="hidden" value="">
            <input name="token" type="hidden" id="token" value="">
            <input id="userfile" name="file" type="file" />

            <!-- take photo with phone -->
            <!-- <input id="userfile" name="file" accept="image/*" type="file" /> -->

            <!-- take video with phone -->
            <!-- <input id="userfile" name="file" type="file" accept="video/*"/> -->

            <input name="accept" type="hidden" />
        </form>

js:
    upload() {
        const formdata = new FormData(document.getElementById('testform'));
        $.ajax({
            url: '上傳的七牛雲服務器,後端提供', // 'http://up.qiniu.com'
            method: 'post',
            success: function(data) {
                console.log(data);
            },
        })
        ...
    }

須要注意的是,每一個input都須要定義好那麼屬性,而且token不能爲空,須要提早經過ajax去後端獲取或者使用後端給定的token不然上傳會失敗~
後續有新的進展繼續更新~

看來仍是不少人不太懂怎麼用,須要個在線demo來玩玩-。-
我擼了個demo,有須要自取~
https://gitee.com/christboy.n...

相關文章
相關標籤/搜索