js怎樣實現文件分片上傳 大文件分片上傳與斷點續傳實戰

文件分片上傳通過將大文件切分為小塊提升上傳效率與穩定性。其核心實現步驟如下:1.前端使用filereader和slice()方法進行文件切割;2.利用fetch或xmlhttprequest逐個上傳分片,并附帶分片索引等元數據;3.通過localstorage記錄已上傳分片實現斷點續傳,后端需存儲并驗證分片狀態;4.服務器接收所有分片后按序合并成完整文件;5.合理選擇4mb-8mb的分片大小以平衡請求次數與失敗率;6.上傳失敗時采用重試機制,設置最大重試次數與延遲間隔;7.監聽上傳進度事件實現ui實時反饋,從而優化用戶體驗。

js怎樣實現文件分片上傳 大文件分片上傳與斷點續傳實戰

文件分片上傳,簡單來說,就是把一個大文件切成很多小塊,一塊一塊地傳到服務器。這樣做的好處顯而易見:提升上傳速度,降低單次上傳失敗的風險,還能實現斷點續傳。

js怎樣實現文件分片上傳 大文件分片上傳與斷點續傳實戰

JS實現文件分片上傳與斷點續傳,核心在于前端的文件切割、上傳控制,以及后端的分片合并。

js怎樣實現文件分片上傳 大文件分片上傳與斷點續傳實戰

解決方案

  1. 前端文件切割: 使用FileReader API讀取文件,然后用slice()方法將文件切割成指定大小的塊。

    js怎樣實現文件分片上傳 大文件分片上傳與斷點續傳實戰

    async function sliceFile(file, chunkSize) {     const chunks = [];     let offset = 0;     while (offset < file.size) {         const chunk = file.slice(offset, offset + chunkSize);         chunks.push(chunk);         offset += chunkSize;     }     return chunks; }
  2. 上傳分片: 使用XMLHttpRequest或fetch API將每個分片上傳到服務器。 每個分片都作為一個獨立的請求發送。

    async function uploadChunk(chunk, fileId, chunkIndex, totalChunks) {     const formData = new FormData();     formData.append('file', chunk);     formData.append('fileId', fileId);     formData.append('chunkIndex', chunkIndex);     formData.append('totalChunks', totalChunks);      try {         const response = await fetch('/upload', {             method: 'POST',             body: formData,         });          if (!response.ok) {             throw new Error(`HTTP error! status: ${response.status}`);         }          const data = await response.json();         return data; // 假設后端返回上傳結果     } catch (error) {         console.error('上傳分片失敗:', error);         throw error; // 向上拋出錯誤,便于后續處理     } }
  3. 斷點續傳: 在上傳過程中,記錄已上傳的分片信息。如果上傳中斷,下次可以從上次中斷的位置繼續上傳。這需要后端配合,記錄已上傳的分片。前端也需要存儲這些信息,例如使用localStorage。

    // 示例:使用localStorage存儲已上傳的分片 function saveUploadedChunk(fileId, chunkIndex) {     let uploadedChunks = JSON.parse(localStorage.getItem(fileId) || '[]');     uploadedChunks.push(chunkIndex);     localStorage.setItem(fileId, JSON.stringify(uploadedChunks)); }  function getUploadedChunks(fileId) {     return JSON.parse(localStorage.getItem(fileId) || '[]'); }
  4. 后端分片合并: 服務器接收到所有分片后,按照分片順序將它們合并成完整的文件。

如何選擇合適的分片大小?

分片大小的選擇直接影響上傳效率和用戶體驗。 太小的分片會導致過多的請求,增加服務器壓力;太大的分片則可能因為網絡不穩定導致單次上傳失敗。一般來說,4MB-8MB是一個比較合適的范圍。 實際應用中,可以根據網絡環境和文件大小進行調整。

如何處理上傳錯誤和重試機制?

上傳過程中,網絡波動、服務器故障等都可能導致上傳失敗。為了提高上傳成功率,需要實現錯誤處理和重試機制。可以設置最大重試次數,每次重試之間增加一定的延遲。 超過最大重試次數后,可以提示用戶稍后重試。

async function retryUpload(chunk, fileId, chunkIndex, totalChunks, maxRetries = 3, delay = 1000) {     let retries = 0;     while (retries < maxRetries) {         try {             return await uploadChunk(chunk, fileId, chunkIndex, totalChunks);         } catch (error) {             console.warn(`分片 ${chunkIndex} 上傳失敗,正在重試 (${retries + 1}/${maxRetries})...`);             retries++;             await new Promise(resolve => setTimeout(resolve, delay)); // 延遲一段時間后重試         }     }     throw new Error(`分片 ${chunkIndex} 上傳達到最大重試次數,上傳失敗。`); }

如何實現上傳進度的實時展示?

實時展示上傳進度可以顯著提升用戶體驗。 可以通過監聽XMLHttpRequest的progress事件,或者fetch API返回的ReadableStream來獲取上傳進度。 將進度信息更新到UI界面上,讓用戶了解上傳狀態。

// 使用 fetch API 監聽上傳進度 async function uploadWithProgress(chunk, fileId, chunkIndex, totalChunks, progressCallback) {     const formData = new FormData();     formData.append('file', chunk);     formData.append('fileId', fileId);     formData.append('chunkIndex', chunkIndex);     formData.append('totalChunks', totalChunks);      const response = await fetch('/upload', {         method: 'POST',         body: formData,         duplex: 'half', // 允許讀取請求體         signal: AbortSignal.timeout(60000) // 設置超時時間     });      if (!response.body) {         throw new Error('Response body is empty.');     }      const reader = response.body.getReader();     const contentLength = response.headers.get('Content-Length');     let receivedLength = 0;      while (true) {         const { done, value } = await reader.read();          if (done) {             break;         }          receivedLength += value.length;         const progress = contentLength ? receivedLength / Number(contentLength) : 0;         progressCallback(progress); // 調用回調函數更新進度     }      if (!response.ok) {         throw new Error(`HTTP error! status: ${response.status}`);     }      const data = await response.json();     return data; }

? 版權聲明
THE END
喜歡就支持一下吧
點贊9 分享