<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      前端-文件上傳幾種方式及其核心思想

      一、文件上傳幾種方式

      1. form表單上傳
      2. iframe
      3. FormData異步上傳

      1、from 表單上傳

      首先要知道我們上傳文件時(shí)需要修改form表單的 enctype='multipart/form-data'
      產(chǎn)生問(wèn)題:
      form表單提交之后會(huì)刷新頁(yè)面
      form表單上傳大文件時(shí),很容易遇見(jiàn)服務(wù)器超時(shí)

      1.1 普通上傳

      <form action="http:localhost:8080/uploadFile" method="POST" enctype="multipart/form-data">
          <input type="file" name="myfile">
          <input type="submit">
      </form>
      

      1.2異步上傳

      方案1:base64上傳

      通過(guò)canvas講圖片裝成base64,然后在服務(wù)端進(jìn)行解碼。
      base64會(huì)將原本的體積轉(zhuǎn)成4/3的體積,so會(huì)增大請(qǐng)求體加,浪費(fèi)帶寬,上傳和解析的時(shí)間會(huì)明顯增加。

      <input type="file" id='file'>
      <canvas id='canvas'></canvas>
      <img src="" id='target-img'>
      <script>
          let canvas = document.getElementById("canvas"),
              targetImg = document.getElementById('target-img'),
              file = document.getElementById('file'),
              context = canvas.getContext('2d')
      
          file.onchange = function() {
              let URL = window.URL || window.webkitURL
              let dataURL = URL.createObjectURL(this.files[0]) // 創(chuàng)建URL對(duì)象
              let img = new Image()
              img.crossOrigin = "anonymous" // 只有服務(wù)器模式打開(kāi), 才有效
              img.src = dataURL
              img.onload = function() {
                  URL.revokeObjectURL(this.src) //  img加載完成后,主動(dòng)釋放URL對(duì)象
                  canvas.width = img.width
                  canvas.height = img.height
                  context.drawImage(img, 0, 0, img.width, img.height)
                  let dataBase64Url = canvas.toDataURL('img/png')
                  targetImg.src = dataBase64Url
              }
      
          }
      </script>
      
      方案2:二進(jìn)制形式

      除了進(jìn)行base64編碼,還可以在前端直接讀取文件內(nèi)容后以二進(jìn)制格式上傳

      關(guān)鍵api:
      參考

      • FileReader:對(duì)象允許Web應(yīng)用程序異步讀取存儲(chǔ)在用戶計(jì)算機(jī)上的文件(或原始數(shù)據(jù)緩沖區(qū))的內(nèi)容,使用 File 或 Blob 對(duì)象指定要讀取的文件或數(shù)據(jù)。

        • File:對(duì)象可以是來(lái)自用戶在一個(gè)<input>元素上選擇文件后返回的files對(duì)象

        • readAsBinaryString: 方法會(huì)讀取指定的 Blob 或 File 對(duì)象,當(dāng)讀取完成的時(shí)候,readyState 會(huì)變成DONE(已完成),并觸發(fā) loadend (en-US) 事件,同時(shí)result 屬性將包含所讀取文件原始二進(jìn)制格式

      • Blob: 前端的一個(gè)專門用于支持文件操作的二進(jìn)制對(duì)象

      • ArrayBuffer:前端的一個(gè)通用的二進(jìn)制緩沖區(qū),類似數(shù)組,但在API和特性上卻有諸多不同

      • Buffer:Node.js提供的一個(gè)二進(jìn)制緩沖區(qū),常用來(lái)處理I/O操作

      • Uint8Array:類型數(shù)組表示的8位無(wú)符號(hào)整數(shù)數(shù)組

      二進(jìn)制上傳

      文件路徑格式轉(zhuǎn)二進(jìn)制

      var reader = new FileReader();//①
      
      reader.readAsBinaryString(file);// 把從input里讀取的文件內(nèi)容,放到fileReader的result字段里
      reader.onload = function(){
      	 readBinary(this.result) // 讀取result或直接上傳
      }
      // 讀取二進(jìn)制文件
      function readBinary(text){
          var data = new ArrayBuffer(text.length);//創(chuàng)建一個(gè)長(zhǎng)度為text.length的二進(jìn)制緩存區(qū)
          var ui8a = new Uint8Array(data, 0);
          for (var i = 0; i < text.length; i++){ 
              ui8a[i] = (text.charCodeAt(i) & 0xff);
          }
          console.log(ui8a)
      }
      

      二進(jìn)制下載
      在向后端發(fā)起請(qǐng)求時(shí),需要在請(qǐng)求頭中加上

      responseType: 'blob'
      

      這樣在返回data中可以得到一個(gè)瀏覽器可以解析的blob數(shù)據(jù)

      	const downURL = window.URL.createObjectURL(new Blob([data]));
      	 // data 為獲取到的二進(jìn)制數(shù)據(jù)
      	const listNode = document.createElement("a");
      	// 這里注意 : 非同源a標(biāo)簽的download去命名沒(méi)有用
      	listNode.download = '合同公允價(jià)錯(cuò)誤文件下載.xlsx';
      	listNode.style.display = "none";
      	listNode.href = downURL;
      
      

      2、frame上傳

      低版本瀏覽器上,xhr請(qǐng)求不支持formdata上傳,只能form表單上傳。
      form表單上傳,出現(xiàn)的問(wèn)題上文已經(jīng)提到,會(huì)本身進(jìn)行頁(yè)面跳轉(zhuǎn),產(chǎn)生原因?yàn)閠arget屬性導(dǎo)致
      target我們或多或少有些了解,a標(biāo)簽也有改屬性:
      _self:默認(rèn)值,在相同的窗口中打開(kāi)響應(yīng)頁(yè)面
      _blank:在新窗口打開(kāi)
      _parent:在父窗口打開(kāi)
      _top:在最頂層的窗口打開(kāi)

      實(shí)現(xiàn)方案
      實(shí)現(xiàn)異步上傳的感覺(jué),自理我們就要用到framename去置頂名字的iframe中打開(kāi),也就是<iframe name='formtarget'></iframe><form target='formtarget'>,這樣一來(lái)返回的數(shù)據(jù)會(huì)被iframe接收,就不會(huì)出現(xiàn)刷新問(wèn)題,而返回的內(nèi)容可以通過(guò)iframe文本拿到。
      問(wèn)題:預(yù)覽圖片只有先傳給后臺(tái),后臺(tái)再返回一個(gè)線上的地址

      <iframe id="iframe1" name="formtarget" style="display: none"></iframe>
      <form id="fm1" action="/app04/ajax1/" method="POST" target="formtarget" enctype="multipart/form-data">
          <input type="file" name="k3"/>
          <input type="submit">
      </form>
      <script>
      file.onchange = function() {
          let iframe = document.getElementById('iframe1')
          iframe.addEventListener("load", function() {
              var content = this.contents().
              var data = JSON.parse(content)
      
          })
      }
      </script>
      

      3、FormData異步上傳

      利用FormData模擬表單數(shù)據(jù),通過(guò)ajax進(jìn)行提交,可以更加靈活地發(fā)送Ajax請(qǐng)求。可以使用FormData來(lái)模擬表單提交。

      let files = e.target.files // 獲取input的file對(duì)象
      let formData = new FormData();
      formData.append('file', file);
      axios.post(url, formData);
      

      二、大文件上傳

      在同一個(gè)請(qǐng)求中,要上傳大量的數(shù)據(jù),導(dǎo)致整個(gè)過(guò)程會(huì)比較漫長(zhǎng),且失敗后需要重頭開(kāi)始上傳

      大文件上傳我們需要考慮三個(gè)方面:

      • 切片:拆分上傳請(qǐng)求
      • 斷點(diǎn)續(xù)傳
      • 顯示上傳進(jìn)度和暫停上傳

      1、切片

      識(shí)別切片來(lái)源
      保證切片拼接順序

      • 我們一般采用編碼的方式進(jìn)行上傳,獲取文件對(duì)應(yīng)的二進(jìn)制內(nèi)容。
      • 計(jì)算出內(nèi)容的總大小,根據(jù)文件大小切成對(duì)應(yīng)的分片。
      • 上傳時(shí)標(biāo)識(shí)出當(dāng)前文件,告訴后端上傳到了第幾個(gè)(可以用時(shí)間戳形式)。
        • 不加表示的話后端在追加切片時(shí),無(wú)法識(shí)別切片順序
        • 接口異常的情況下無(wú)法正確拼接

      實(shí)現(xiàn)
      根據(jù)文件名、文件長(zhǎng)度等基本信息進(jìn)行拼接,為了避免多個(gè)用戶上傳相同的文件,可以再額外拼接用戶信息如uid等保證唯一性
      根據(jù)文件的二進(jìn)制內(nèi)容計(jì)算文件的hash,這樣只要文件內(nèi)容不一樣,則標(biāo)識(shí)也會(huì)不一樣,缺點(diǎn)在于計(jì)算量比較大.
      將文件拆分成piece大小的分塊,然后每次請(qǐng)求只需要上傳這一個(gè)部分的分塊即可

       let file = document.querySelector("[name=file]").files[0];
      const LENGTH = 1024 * 1024 * 0.1;
      let chunks = sliceFile(file, LENGTH); // 首先拆分切片
      chunks.forEach((chunk,index) => {
      
          let fd = new FormData();
          fd.append("file", chunk);
          // 傳遞context
          fd.append("context", file.name + file.length);
          // 傳遞切片索引值
          fd.append("chunk", index + 1);
      
          upload(fd)    
      })
      
        function sliceFile(file, piece = 1024 * 1024 * 5) {
              let totalSize = file.size; // 文件總大小
      
              let start = 0; // 每次上傳的開(kāi)始字節(jié)
              let end = start + piece; // 每次上傳的結(jié)尾字節(jié)
              let chunks = []
      
              while (start < totalSize) {
                  // 根據(jù)長(zhǎng)度截取每次需要上傳的數(shù)據(jù)
                  // File對(duì)象繼承自Blob對(duì)象,因此包含slice方法
                  let blob = file.slice(start, end);
                  chunks.push(blob)
                  start = end;
      
                  end = start + piece;
              }
              return chunks
          }
      

      請(qǐng)求

      /**
       * 文件上傳  
       * @param {} params
       */
      export function upload (params) {
        const data = new FormData();
        data.append('file', params.file);
        data.append('type', params.type);
        return $axios({
          method: 'post',
          url: "/api/Files/upload",
          data: data,
          headers: {
            'Content-Type': 'multipart/form-data',
          }
        })
      }
      

      2、斷點(diǎn)續(xù)傳

      我們?cè)谏蟼骰蛘呦螺d文件的時(shí)候,如果已經(jīng)進(jìn)行了一部分,這時(shí)候網(wǎng)絡(luò)故障、頁(yè)面關(guān)閉的情況下,不需要從頭開(kāi)始操作,而是從指定位置繼續(xù)進(jìn)行操作,這種處理方式就是所說(shuō)的“斷點(diǎn)續(xù)傳”

      斷點(diǎn):的由來(lái)是在下載過(guò)程中,將一個(gè)下載文件分成了多個(gè)部分,同時(shí)進(jìn)行多個(gè)部分一起的下載,當(dāng)某個(gè)時(shí)間點(diǎn),任務(wù)被暫停了,此時(shí)下載暫停的位置就是斷點(diǎn)了。
      續(xù)傳:一個(gè)任務(wù)從暫停到開(kāi)始時(shí),會(huì)從上一次任務(wù)暫停處開(kāi)始(可以每次傳輸成功后加一個(gè)表示為告訴前端傳輸進(jìn)度)。

      實(shí)現(xiàn)思路:

      • 保存已上傳的切片信息
      • 選擇未上傳的切片進(jìn)行上傳
      • 全部上傳成功后后端進(jìn)行文件合并

      實(shí)現(xiàn)方案:

      1. 本地存儲(chǔ):我們可以利用localstorage,cookie等方式存儲(chǔ)在瀏覽器內(nèi),這種情況下我們不依賴于后端,直接本地讀取就行。清理了本地文件,會(huì)導(dǎo)致上傳記錄丟失。
      2. 其實(shí)服務(wù)器知道我們已經(jīng)傳輸?shù)搅四男┣衅切┻M(jìn)度,我們通過(guò)接口去傳輸為上傳的切片即可。

      3、上傳進(jìn)度和暫停

      進(jìn)度:我們可以利用xhr.upload.onprogress = Function方法做進(jìn)度的監(jiān)聽(tīng)

      xhr.upload.onprogress = function(e) {
          if (e.lengthComputable) {
              var percent = Math.floor( e.loaded / e.total * 100);//進(jìn)度計(jì)算
              if(percent == 100){
                 
              }else{
                 
              }
          }
      };
      
      

      暫停:如果該請(qǐng)求已被發(fā)出,XMLHttpRequest.abort() 方法將終止該請(qǐng)求,實(shí)現(xiàn)上傳暫停的效果。
      繼續(xù):和斷點(diǎn)繼傳類似,先獲取傳輸?shù)牧斜恚缓笾匦掳l(fā)送未上傳的切片。

      posted @ 2022-03-31 16:47  雅痞_yuppie  閱讀(6133)  評(píng)論(0)    收藏  舉報(bào)
      主站蜘蛛池模板: 中文字幕人妻互换av久久| 久久精品国产亚洲av久| 亚洲国产成人精品女久久| 国产AV巨作丝袜秘书| 无码人妻斩一区二区三区| 一级女性全黄久久片免费| 欧美视频免费一区二区三区| 国产精品视频一区不卡| 国产亚洲精品成人av久| 在线看免费无码的av天堂| 国产无遮挡无码视频在线观看| 国产精品老熟女乱一区二区| 成人麻豆日韩在无码视频| 亚洲特黄色片一区二区三区| 成人无码午夜在线观看| 欧美另类精品xxxx人妖| 四虎永久在线精品无码视频| 深夜国产成人福利在线观看| 亚洲国产精品一区在线看| 国产片AV国语在线观看手机版| 国产av激情无码久久| 国产精品99久久久久久www| 午夜DY888国产精品影院| 欧美牲交a欧美牲交aⅴ图片| 午夜福利理论片高清在线| 亚洲高清乱码午夜电影网| 高尔夫| 国产一区二区av天堂热| 无码人妻精品一区二区在线视频| 推特国产午夜福利在线观看| 偷拍专区一区二区三区| 草草浮力影院| 国产在线国偷精品产拍| 国产在线视频导航| 国产区精品视频自产自拍| 日本边添边摸边做边爱喷水| 成年午夜性影院| 亚洲天天堂天堂激情性色| 大石桥市| 久久这里有精品国产电影网| 亚洲a免费|