• <center id="sm46c"></center>
  • <dfn id="sm46c"></dfn>
  • <strike id="sm46c"></strike>
  • <cite id="sm46c"><source id="sm46c"></source></cite>
    • <strike id="sm46c"><source id="sm46c"></source></strike>
      <option id="sm46c"></option>
      国产精品天天看天天狠,女高中生强奷系列在线播放,久久无码免费的a毛片大全,国产日韩综合av在线,亚洲国产中文综合专区在,特殊重囗味sm在线观看无码,中文字幕一区二区三区四区在线,无码任你躁久久久久久老妇蜜桃

      VUE-多文件斷點(diǎn)續(xù)傳、秒傳、分片上傳

      2020-7-20    seo達(dá)人

      凡是要知其然知其所以然

      文件上傳相信很多朋友都有遇到過,那或許你也遇到過當(dāng)上傳大文件時(shí),上傳時(shí)間較長(zhǎng),且經(jīng)常失敗的困擾,并且失敗后,又得重新上傳很是煩人。那我們先了解下失敗的原因吧!


      據(jù)我了解大概有以下原因:


      服務(wù)器配置:例如在PHP中默認(rèn)的文件上傳大小為8M【post_max_size = 8m】,若你在一個(gè)請(qǐng)求體中放入8M以上的內(nèi)容時(shí),便會(huì)出現(xiàn)異常

      請(qǐng)求超時(shí):當(dāng)你設(shè)置了接口的超時(shí)時(shí)間為10s,那么上傳大文件時(shí),一個(gè)接口響應(yīng)時(shí)間超過10s,那么便會(huì)被Faild掉。

      網(wǎng)絡(luò)波動(dòng):這個(gè)就屬于不可控因素,也是較常見的問題。

      基于以上原因,聰明的人們就想到了,將文件拆分多個(gè)小文件,依次上傳,不就解決以上1,2問題嘛,這便是分片上傳。 網(wǎng)絡(luò)波動(dòng)這個(gè)實(shí)在不可控,也許一陣大風(fēng)刮來,就斷網(wǎng)了呢。那這樣好了,既然斷網(wǎng)無法控制,那我可以控制只上傳已經(jīng)上傳的文件內(nèi)容,不就好了,這樣大大加快了重新上傳的速度。所以便有了“斷點(diǎn)續(xù)傳”一說。此時(shí),人群中有人插了一嘴,有些文件我已經(jīng)上傳一遍了,為啥還要在上傳,能不能不浪費(fèi)我流量和時(shí)間。喔...這個(gè)嘛,簡(jiǎn)單,每次上傳時(shí)判斷下是否存在這個(gè)文件,若存在就不重新上傳便可,于是又有了“秒傳”一說。從此這"三兄弟" 便自行CP,統(tǒng)治了整個(gè)文件界?!?

      注意文中的代碼并非實(shí)際代碼,請(qǐng)移步至github查看代碼

      https://github.com/pseudo-god...


      分片上傳

      HTML

      原生INPUT樣式較丑,這里通過樣式疊加的方式,放一個(gè)Button.

       <div class="btns">

         <el-button-group>

           <el-button :disabled="changeDisabled">

             <i class="el-icon-upload2 el-icon--left" size="mini"></i>選擇文件

             <input

               v-if="!changeDisabled"

               type="file"

               :multiple="multiple"

               class="select-file-input"

               :accept="accept"

               @change="handleFileChange"

             />

           </el-button>

           <el-button :disabled="uploadDisabled" @click="handleUpload()"><i class="el-icon-upload el-icon--left" size="mini"></i>上傳</el-button>

           <el-button :disabled="pauseDisabled" @click="handlePause"><i class="el-icon-video-pause el-icon--left" size="mini"></i>暫停</el-button>

           <el-button :disabled="resumeDisabled" @click="handleResume"><i class="el-icon-video-play el-icon--left" size="mini"></i>恢復(fù)</el-button>

           <el-button :disabled="clearDisabled" @click="clearFiles"><i class="el-icon-video-play el-icon--left" size="mini"></i>清空</el-button>

         </el-button-group>

         <slot

         

      //data 數(shù)據(jù)


      var chunkSize = 10 * 1024 * 1024; // 切片大小

      var fileIndex = 0; // 當(dāng)前正在被遍歷的文件下標(biāo)


      data: () => ({

         container: {

           files: null

         },

         tempFilesArr: [], // 存儲(chǔ)files信息

         cancels: [], // 存儲(chǔ)要取消的請(qǐng)求

         tempThreads: 3,

         // 默認(rèn)狀態(tài)

         status: Status.wait

       }),

         

      一個(gè)稍微好看的UI就出來了。




      選擇文件

      選擇文件過程中,需要對(duì)外暴露出幾個(gè)鉤子,熟悉elementUi的同學(xué)應(yīng)該很眼熟,這幾個(gè)鉤子基本與其一致。onExceed:文件超出個(gè)數(shù)限制時(shí)的鉤子、beforeUpload:文件上傳之前

      fileIndex 這個(gè)很重要,因?yàn)槭嵌辔募蟼?,所以定位?dāng)前正在被上傳的文件就很重要,基本都靠它


      handleFileChange(e) {

       const files = e.target.files;

       if (!files) return;

       Object.assign(this.$data, this.$options.data()); // 重置data所有數(shù)據(jù)


       fileIndex = 0; // 重置文件下標(biāo)

       this.container.files = files;

       // 判斷文件選擇的個(gè)數(shù)

       if (this.limit && this.container.files.length > this.limit) {

         this.onExceed && this.onExceed(files);

         return;

       }


       // 因filelist不可編輯,故拷貝filelist 對(duì)象

       var index = 0; // 所選文件的下標(biāo),主要用于剔除文件后,原文件list與臨時(shí)文件list不對(duì)應(yīng)的情況

       for (const key in this.container.files) {

         if (this.container.files.hasOwnProperty(key)) {

           const file = this.container.files[key];


           if (this.beforeUpload) {

             const before = this.beforeUpload(file);

             if (before) {

               this.pushTempFile(file, index);

             }

           }


           if (!this.beforeUpload) {

             this.pushTempFile(file, index);

           }


           index++;

         }

       }

      },

      // 存入 tempFilesArr,為了上面的鉤子,所以將代碼做了拆分

      pushTempFile(file, index) {

       // 額外的初始值

       const obj = {

         status: fileStatus.wait,

         chunkList: [],

         uploadProgress: 0,

         hashProgress: 0,

         index

       };

       for (const k in file) {

         obj[k] = file[k];

       }

       console.log('pushTempFile -> obj', obj);

       this.tempFilesArr.push(obj);

      }

      分片上傳

      創(chuàng)建切片,循環(huán)分解文件即可


       createFileChunk(file, size = chunkSize) {

         const fileChunkList = [];

         var count = 0;

         while (count < file.size) {

           fileChunkList.push({

             file: file.slice(count, count + size)

           });

           count += size;

         }

         return fileChunkList;

       }

      循環(huán)創(chuàng)建切片,既然咱們做的是多文件,所以這里就有循環(huán)去處理,依次創(chuàng)建文件切片,及切片的上傳。

      async handleUpload(resume) {

       if (!this.container.files) return;

       this.status = Status.uploading;

       const filesArr = this.container.files;

       var tempFilesArr = this.tempFilesArr;


       for (let i = 0; i < tempFilesArr.length; i++) {

         fileIndex = i;

         //創(chuàng)建切片

         const fileChunkList = this.createFileChunk(

           filesArr[tempFilesArr[i].index]

         );

           

         tempFilesArr[i].fileHash ='xxxx'; // 先不用看這個(gè),后面會(huì)講,占個(gè)位置

         tempFilesArr[i].chunkList = fileChunkList.map(({ file }, index) => ({

           fileHash: tempFilesArr[i].hash,

           fileName: tempFilesArr[i].name,

           index,

           hash: tempFilesArr[i].hash + '-' + index,

           chunk: file,

           size: file.size,

           uploaded: false,

           progress: 0, // 每個(gè)塊的上傳進(jìn)度

           status: 'wait' // 上傳狀態(tài),用作進(jìn)度狀態(tài)顯示

         }));

         

         //上傳切片

         await this.uploadChunks(this.tempFilesArr[i]);

       }

      }

      上傳切片,這個(gè)里需要考慮的問題較多,也算是核心吧,uploadChunks方法只負(fù)責(zé)構(gòu)造傳遞給后端的數(shù)據(jù),核心上傳功能放到sendRequest方法中

      async uploadChunks(data) {

       var chunkData = data.chunkList;

       const requestDataList = chunkData

         .map(({ fileHash, chunk, fileName, index }) => {

           const formData = new FormData();

           formData.append('md5', fileHash);

           formData.append('file', chunk);

           formData.append('fileName', index); // 文件名使用切片的下標(biāo)

           return { formData, index, fileName };

         });


       try {

         await this.sendRequest(requestDataList, chunkData);

       } catch (error) {

         // 上傳有被reject的

         this.$message.error('親 上傳失敗了,考慮重試下呦' + error);

         return;

       }


       // 合并切片

       const isUpload = chunkData.some(item => item.uploaded === false);

       console.log('created -> isUpload', isUpload);

       if (isUpload) {

         alert('存在失敗的切片');

       } else {

         // 執(zhí)行合并

         await this.mergeRequest(data);

       }

      }

      sendReques。上傳這是最重要的地方,也是容易失敗的地方,假設(shè)有10個(gè)分片,那我們?nèi)羰侵苯影l(fā)10個(gè)請(qǐng)求的話,很容易達(dá)到瀏覽器的瓶頸,所以需要對(duì)請(qǐng)求進(jìn)行并發(fā)處理。


      并發(fā)處理:這里我使用for循環(huán)控制并發(fā)的初始并發(fā)數(shù),然后在 handler 函數(shù)里調(diào)用自己,這樣就控制了并發(fā)。在handler中,通過數(shù)組API.shift模擬隊(duì)列的效果,來上傳切片。

      重試: retryArr 數(shù)組存儲(chǔ)每個(gè)切片文件請(qǐng)求的重試次數(shù),做累加。比如[1,0,2],就是第0個(gè)文件切片報(bào)錯(cuò)1次,第2個(gè)報(bào)錯(cuò)2次。為保證能與文件做對(duì)應(yīng),const index = formInfo.index; 我們直接從數(shù)據(jù)中拿之前定義好的index。 若失敗后,將失敗的請(qǐng)求重新加入隊(duì)列即可。


      關(guān)于并發(fā)及重試我寫了一個(gè)小Demo,若不理解可以自己在研究下,文件地址:https://github.com/pseudo-god... , 重試代碼好像被我弄丟了,大家要是有需求,我再補(bǔ)吧!

         // 并發(fā)處理

      sendRequest(forms, chunkData) {

       var finished = 0;

       const total = forms.length;

       const that = this;

       const retryArr = []; // 數(shù)組存儲(chǔ)每個(gè)文件hash請(qǐng)求的重試次數(shù),做累加 比如[1,0,2],就是第0個(gè)文件切片報(bào)錯(cuò)1次,第2個(gè)報(bào)錯(cuò)2次


       return new Promise((resolve, reject) => {

         const handler = () => {

           if (forms.length) {

             // 出棧

             const formInfo = forms.shift();


             const formData = formInfo.formData;

             const index = formInfo.index;

             

             instance.post('fileChunk', formData, {

               onUploadProgress: that.createProgresshandler(chunkData[index]),

               cancelToken: new CancelToken(c => this.cancels.push(c)),

               timeout: 0

             }).then(res => {

               console.log('handler -> res', res);

               // 更改狀態(tài)

               chunkData[index].uploaded = true;

               chunkData[index].status = 'success';

               

               finished++;

               handler();

             })

               .catch(e => {

                 // 若暫停,則禁止重試

                 if (this.status === Status.pause) return;

                 if (typeof retryArr[index] !== 'number') {

                   retryArr[index] = 0;

                 }


                 // 更新狀態(tài)

                 chunkData[index].status = 'warning';


                 // 累加錯(cuò)誤次數(shù)

                 retryArr[index]++;


                 // 重試3次

                 if (retryArr[index] >= this.chunkRetry) {

                   return reject('重試失敗', retryArr);

                 }


                 this.tempThreads++; // 釋放當(dāng)前占用的通道


                 // 將失敗的重新加入隊(duì)列

                 forms.push(formInfo);

                 handler();

               });

           }


           if (finished >= total) {

             resolve('done');

           }

         };


         // 控制并發(fā)

         for (let i = 0; i < this.tempThreads; i++) {

           handler();

         }

       });

      }

      切片的上傳進(jìn)度,通過axios的onUploadProgress事件,結(jié)合createProgresshandler方法進(jìn)行維護(hù)

      // 切片上傳進(jìn)度

      createProgresshandler(item) {

       return p => {

         item.progress = parseInt(String((p.loaded / p.total) * 100));

         this.fileProgress();

       };

      }

      Hash計(jì)算

      其實(shí)就是算一個(gè)文件的MD5值,MD5在整個(gè)項(xiàng)目中用到的地方也就幾點(diǎn)。

      秒傳,需要通過MD5值判斷文件是否已存在。

      續(xù)傳:需要用到MD5作為key值,當(dāng)唯一值使用。

      本項(xiàng)目主要使用worker處理,性能及速度都會(huì)有很大提升.

      由于是多文件,所以HASH的計(jì)算進(jìn)度也要體現(xiàn)在每個(gè)文件上,所以這里使用全局變量fileIndex來定位當(dāng)前正在被上傳的文件

      執(zhí)行計(jì)算hash


      正在上傳文件


      // 生成文件 hash(web-worker)

      calculateHash(fileChunkList) {

       return new Promise(resolve => {

         this.container.worker = new Worker('./hash.js');

         this.container.worker.postMessage({ fileChunkList });

         this.container.worker.onmessage = e => {

           const { percentage, hash } = e.data;

           if (this.tempFilesArr[fileIndex]) {

             this.tempFilesArr[fileIndex].hashProgress = Number(

               percentage.toFixed(0)

             );

           }


           if (hash) {

             resolve(hash);

           }

         };

       });

      }

      因使用worker,所以我們不能直接使用NPM包方式使用MD5。需要單獨(dú)去下載spark-md5.js文件,并引入


      //hash.js


      self.importScripts("/spark-md5.min.js"); // 導(dǎo)入腳本

      // 生成文件 hash

      self.onmessage = e => {

       const { fileChunkList } = e.data;

       const spark = new self.SparkMD5.ArrayBuffer();

       let percentage = 0;

       let count = 0;

       const loadNext = index => {

         const reader = new FileReader();

         reader.readAsArrayBuffer(fileChunkList[index].file);

         reader.onload = e => {

           count++;

           spark.append(e.target.result);

           if (count === fileChunkList.length) {

             self.postMessage({

               percentage: 100,

               hash: spark.end()

             });

             self.close();

           } else {

             percentage += 100 / fileChunkList.length;

             self.postMessage({

               percentage

             });

             loadNext(count);

           }

         };

       };

       loadNext(0);

      };

      文件合并

      當(dāng)我們的切片全部上傳完畢后,就需要進(jìn)行文件的合并,這里我們只需要請(qǐng)求接口即可

      mergeRequest(data) {

        const obj = {

          md5: data.fileHash,

          fileName: data.name,

          fileChunkNum: data.chunkList.length

        };


        instance.post('fileChunk/merge', obj,

          {

            timeout: 0

          })

          .then((res) => {

            this.$message.success('上傳成功');

          });

      }

      Done: 至此一個(gè)分片上傳的功能便已完成

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

      顧名思義,就是從那斷的就從那開始,明確思路就很簡(jiǎn)單了。一般有2種方式,一種為服務(wù)器端返回,告知我從那開始,還有一種是瀏覽器端自行處理。2種方案各有優(yōu)缺點(diǎn)。本項(xiàng)目使用第二種。

      思路:已文件HASH為key值,每個(gè)切片上傳成功后,記錄下來便可。若需要續(xù)傳時(shí),直接跳過記錄中已存在的便可。本項(xiàng)目將使用Localstorage進(jìn)行存儲(chǔ),這里我已提前封裝好addChunkStorage、getChunkStorage方法。


      存儲(chǔ)在Stroage的數(shù)據(jù)




      緩存處理

      在切片上傳的axios成功回調(diào)中,存儲(chǔ)已上傳成功的切片


      instance.post('fileChunk', formData, )

       .then(res => {

         // 存儲(chǔ)已上傳的切片下標(biāo)

      + this.addChunkStorage(chunkData[index].fileHash, index);

         handler();

       })

      在切片上傳前,先看下localstorage中是否存在已上傳的切片,并修改uploaded


         async handleUpload(resume) {

      +      const getChunkStorage = this.getChunkStorage(tempFilesArr[i].hash);

           tempFilesArr[i].chunkList = fileChunkList.map(({ file }, index) => ({

      +        uploaded: getChunkStorage && getChunkStorage.includes(index), // 標(biāo)識(shí):是否已完成上傳

      +        progress: getChunkStorage && getChunkStorage.includes(index) ? 100 : 0,

      +        status: getChunkStorage && getChunkStorage.includes(index)? 'success'

      +              : 'wait' // 上傳狀態(tài),用作進(jìn)度狀態(tài)顯示

           }));


         }

      構(gòu)造切片數(shù)據(jù)時(shí),過濾掉uploaded為true的


      async uploadChunks(data) {

       var chunkData = data.chunkList;

       const requestDataList = chunkData

      +    .filter(({ uploaded }) => !uploaded)

         .map(({ fileHash, chunk, fileName, index }) => {

           const formData = new FormData();

           formData.append('md5', fileHash);

           formData.append('file', chunk);

           formData.append('fileName', index); // 文件名使用切片的下標(biāo)

           return { formData, index, fileName };

         })

      }

      垃圾文件清理

      隨著上傳文件的增多,相應(yīng)的垃圾文件也會(huì)增多,比如有些時(shí)候上傳一半就不再繼續(xù),或上傳失敗,碎片文件就會(huì)增多。解決方案我目前想了2種

      前端在localstorage設(shè)置緩存時(shí)間,超過時(shí)間就發(fā)送請(qǐng)求通知后端清理碎片文件,同時(shí)前端也要清理緩存。

      前后端都約定好,每個(gè)緩存從生成開始,只能存儲(chǔ)12小時(shí),12小時(shí)后自動(dòng)清理

      以上2中方案似乎都有點(diǎn)問題,極有可能造成前后端因時(shí)間差,引發(fā)切片上傳異常的問題,后面想到合適的解決方案再來更新吧。

      Done: 續(xù)傳到這里也就完成了。


      秒傳

      這算是最簡(jiǎn)單的,只是聽起來很厲害的樣子。原理:計(jì)算整個(gè)文件的HASH,在執(zhí)行上傳操作前,向服務(wù)端發(fā)送請(qǐng)求,傳遞MD5值,后端進(jìn)行文件檢索。若服務(wù)器中已存在該文件,便不進(jìn)行后續(xù)的任何操作,上傳也便直接結(jié)束。大家一看就明白

      async handleUpload(resume) {

         if (!this.container.files) return;

         const filesArr = this.container.files;

         var tempFilesArr = this.tempFilesArr;


         for (let i = 0; i < tempFilesArr.length; i++) {

           const fileChunkList = this.createFileChunk(

             filesArr[tempFilesArr[i].index]

           );


           // hash校驗(yàn),是否為秒傳

      +      tempFilesArr[i].hash = await this.calculateHash(fileChunkList);

      +      const verifyRes = await this.verifyUpload(

      +        tempFilesArr[i].name,

      +        tempFilesArr[i].hash

      +      );

      +      if (verifyRes.data.presence) {

      +       tempFilesArr[i].status = fileStatus.secondPass;

      +       tempFilesArr[i].uploadProgress = 100;

      +      } else {

             console.log('開始上傳切片文件----》', tempFilesArr[i].name);

             await this.uploadChunks(this.tempFilesArr[i]);

           }

         }

       }

       // 文件上傳之前的校驗(yàn): 校驗(yàn)文件是否已存在

       verifyUpload(fileName, fileHash) {

         return new Promise(resolve => {

           const obj = {

             md5: fileHash,

             fileName,

             ...this.uploadArguments //傳遞其他參數(shù)

           };

           instance

             .post('fileChunk/presence', obj)

             .then(res => {

               resolve(res.data);

             })

             .catch(err => {

               console.log('verifyUpload -> err', err);

             });

         });

       }

      Done: 秒傳到這里也就完成了。

      后端處理

      文章好像有點(diǎn)長(zhǎng)了,具體代碼邏輯就先不貼了,除非有人留言要求,嘻嘻,有時(shí)間再更新

      Node版

      請(qǐng)前往 https://github.com/pseudo-god... 查看

      JAVA版

      下周應(yīng)該會(huì)更新處理

      PHP版

      1年多沒寫PHP了,抽空我會(huì)慢慢補(bǔ)上來

      待完善

      切片的大?。哼@個(gè)后面會(huì)做出動(dòng)態(tài)計(jì)算的。需要根據(jù)當(dāng)前所上傳文件的大小,自動(dòng)計(jì)算合適的切片大小。避免出現(xiàn)切片過多的情況。

      文件追加:目前上傳文件過程中,不能繼續(xù)選擇文件加入隊(duì)列。(這個(gè)沒想好應(yīng)該怎么處理。)

      更新記錄

      組件已經(jīng)運(yùn)行一段時(shí)間了,期間也測(cè)試出幾個(gè)問題,本來以為沒BUG的,看起來BUG都挺嚴(yán)重

      BUG-1:當(dāng)同時(shí)上傳多個(gè)內(nèi)容相同但是文件名稱不同的文件時(shí),出現(xiàn)上傳失敗的問題。


      預(yù)期結(jié)果:第一個(gè)上傳成功后,后面相同的問文件應(yīng)該直接秒傳


      實(shí)際結(jié)果:第一個(gè)上傳成功后,其余相同的文件都失敗,錯(cuò)誤信息,塊數(shù)不對(duì)。


      原因:當(dāng)?shù)谝粋€(gè)文件塊上傳完畢后,便立即進(jìn)行了下一個(gè)文件的循環(huán),導(dǎo)致無法及時(shí)獲取文件是否已秒傳的狀態(tài),從而導(dǎo)致失敗。


      解決方案:在當(dāng)前文件分片上傳完畢并且請(qǐng)求合并接口完畢后,再進(jìn)行下一次循環(huán)。


      將子方法都改為同步方式,mergeRequest 和 uploadChunks 方法





      BUG-2: 當(dāng)每次選擇相同的文件并觸發(fā)beforeUpload方法時(shí),若第二次也選擇了相同的文件,beforeUpload方法失效,從而導(dǎo)致整個(gè)流程失效。

      原因:之前每次選擇文件時(shí),沒有清空上次所選input文件的數(shù)據(jù),相同數(shù)據(jù)的情況下,是不會(huì)觸發(fā)input的change事件。


      解決方案:每次點(diǎn)擊input時(shí),清空數(shù)據(jù)即可。我順帶優(yōu)化了下其他的代碼,具體看提交記錄吧。


      <input

       v-if="!changeDisabled"

       type="file"

       :multiple="multiple"

       class="select-file-input"

       :accept="accept"

      +  οnclick="f.outerHTML=f.outerHTML"

       @change="handleFileChange"/>

      重寫了暫停和恢復(fù)的功能,實(shí)際上,主要是增加了暫停和恢復(fù)的狀態(tài)





      之前的處理邏輯太簡(jiǎn)單粗暴,存在諸多問題。現(xiàn)在將狀態(tài)定位在每一個(gè)文件之上,這樣恢復(fù)上傳時(shí),直接跳過即可





      封裝組件

      寫了一大堆,其實(shí)以上代碼你直接復(fù)制也無法使用,這里我將此封裝了一個(gè)組件。大家可以去github下載文件,里面有使用案例 ,若有用記得隨手給個(gè)star,謝謝!

      偷個(gè)懶,具體封裝組件的代碼就不列出來了,大家直接去下載文件查看,若有不明白的,可留言。


      組件文檔

      Attribute

      參數(shù) 類型 說明 默認(rèn) 備注

      headers Object 設(shè)置請(qǐng)求頭

      before-upload Function 上傳文件前的鉤子,返回false則停止上傳

      accept String 接受上傳的文件類型

      upload-arguments Object 上傳文件時(shí)攜帶的參數(shù)

      with-credentials Boolean 是否傳遞Cookie false

      limit Number 最大允許上傳個(gè)數(shù) 0 0為不限制

      on-exceed Function 文件超出個(gè)數(shù)限制時(shí)的鉤子

      multiple Boolean 是否為多選模式 true

      base-url String 由于本組件為內(nèi)置的AXIOS,若你需要走代理,可以直接在這里配置你的基礎(chǔ)路徑

      chunk-size Number 每個(gè)切片的大小 10M

      threads Number 請(qǐng)求的并發(fā)數(shù) 3 并發(fā)數(shù)越高,對(duì)服務(wù)器的性能要求越高,盡可能用默認(rèn)值即可

      chunk-retry Number 錯(cuò)誤重試次數(shù) 3 分片請(qǐng)求的錯(cuò)誤重試次數(shù)

      Slot

      方法名 說明 參數(shù) 備注

      header 按鈕區(qū)域 無

      tip 提示說明文字 無

      后端接口文檔:按文檔實(shí)現(xiàn)即可

      藍(lán)藍(lán)設(shè)計(jì)www.li-bodun.cn )是一家專注而深入的界面設(shè)計(jì)公司,為期望卓越的國(guó)內(nèi)外企業(yè)提供卓越的UI界面設(shè)計(jì)、BS界面設(shè)計(jì) 、 cs界面設(shè)計(jì) 、 ipad界面設(shè)計(jì) 、 包裝設(shè)計(jì) 、 圖標(biāo)定制 、 用戶體驗(yàn) 、交互設(shè)計(jì)、 網(wǎng)站建設(shè) 、平面設(shè)計(jì)服務(wù)






      日歷

      鏈接

      個(gè)人資料

      存檔

      主站蜘蛛池模板: 亚洲线精品一区二区三区 | 国产无码swag专区| 久久棈精品久久久久久噜噜| 精品一区二区亚洲国产| 四虎国产精品永久在线| 东京热无码av一区二区| 午夜精品久久久久久久无码软件| 亚洲av永久一区二区| 国产精品不卡一区二区久久| 日韩高清不卡免费一区二区| 国产亚洲精品线观看k频道| 国产无av码在线观看| 性一交一乱一伦一视频一二三区| 国产爆乳无码一区二区麻豆| 亚洲天堂男人天堂女人天堂| 国产精品3p视频| 亚洲日本欧洲二区精品| 成年人免费国产视频| 亚洲精品一二区| 亚洲激情一区二区三区视频| 成人av天堂网在线观看| 呦系列视频一区二区三区| 亚洲精品一区二区天堂| 国产成人免费高清激情视频| 国产精品亚洲А∨怡红院| 国产亚洲综合另类色专区| 视频一区视频二区中文字幕| 国产国产成人精品久久蜜| 麻豆国产AV剧情偷闻女邻居内裤| 在线播放国产女同闺蜜| 国产精品自在线拍国产| 国产在线观看黄| 国产精品揄拍100视频| 国产精品天天狠天天看| 久久精品精选| 女人乱人伦国产在线观看| 国产做a爱免费视频在线观看| 国产久草视频| 26uuu另类亚洲欧美日本| 国产suv精品一区二区四| 亚洲人成网站免费播放|