js如何實現文件下載功能 前端文件下載的3種實現方法!

1.最簡單的方法是使用標簽+download屬性,直接設置href和download屬性即可,適用于同源文件下載;2.通過window.location.href利用javascript觸發下載,原理與第一種方法相同,但同樣受限于同源策略;3.使用blob對象和url.createobjecturl,通過fetch獲取文件數據并轉為blob對象,再創建臨時url實現下載,支持跨域、可自定義請求頭及控制下載進度。針對大文件下載優化用戶體驗可通過監聽onprogress事件顯示下載進度、添加range請求頭實現斷點續傳、使用web workers將下載任務移至后臺線程避免阻塞主線程。處理下載失敗情況包括:捕獲fetch錯誤、檢查http狀態碼、設置重試機制提高成功率、記錄錯誤日志便于排查問題。

js如何實現文件下載功能 前端文件下載的3種實現方法!

前端文件下載,簡單來說,就是讓用戶點擊一個按鈕或者鏈接,瀏覽器就能自動下載一個文件到本地。這事兒聽起來簡單,但實現起來還是有幾種不同的路子。

js如何實現文件下載功能 前端文件下載的3種實現方法!

直接輸出解決方案即可

js如何實現文件下載功能 前端文件下載的3種實現方法!

  1. 最簡單的: 標簽 + download 屬性

    立即學習前端免費學習筆記(深入)”;

    js如何實現文件下載功能 前端文件下載的3種實現方法!

    這是最直接,也是最常用的方法。你只需要一個標簽,然后設置href屬性為文件的URL,再加一個download屬性,指定下載的文件名就行了。

    <a href="path/to/your/file.pdf" download="自定義文件名.pdf">下載PDF</a>

    這種方法的好處是簡單粗暴,瀏覽器原生支持,兼容性好。但缺點也很明顯,它只能下載同源的文件,如果文件在不同的域名下,瀏覽器會阻止下載,除非服務器允許跨域。而且,這種方式無法控制下載進度,也無法自定義請求頭。

  2. 利用 window.location.href

    這種方法其實跟第一種類似,只不過是通過JavaScript來觸發下載。

    function downloadFile(url) {   window.location.href = url; }  // 調用 downloadFile('path/to/your/file.pdf');

    它的優缺點和第一種方法基本一樣,也是簡單方便,但受限于同源策略,無法控制下載過程。

  3. 使用 Blob 對象和 URL.createObjectURL

    這種方法是目前最靈活,也是最常用的方法。它可以下載任何文件,無論是否同源,而且可以自定義請求頭,控制下載進度。

    function downloadFile(url, filename) {   fetch(url, {     method: 'GET',     // 可以添加自定義請求頭     headers: {       'Authorization': 'Bearer your_token'     }   })   .then(res => res.blob())   .then(blob => {     const a = document.createElement('a');     const url = URL.createObjectURL(blob);     a.href = url;     a.download = filename; // 自定義文件名     document.body.appendChild(a);     a.click();     document.body.removeChild(a);     URL.revokeObjectURL(url); // 釋放URL對象   }); }  // 調用 downloadFile('path/to/your/file.pdf', '自定義文件名.pdf');

    這種方法的核心在于:

    • fetch:發起網絡請求,獲取文件數據。可以設置自定義請求頭,比如Authorization,用于身份驗證。
    • blob():將響應數據轉換為 Blob 對象。Blob 對象表示一個不可變的、原始數據的類文件對象。
    • URL.createObjectURL(blob):創建一個指向 Blob 對象的URL。這個URL可以被標簽使用。
    • URL.revokeObjectURL(url):釋放URL對象,防止內存泄漏。

    這種方法的優點是:

    • 可以下載任何文件,不受同源策略限制。
    • 可以自定義請求頭,進行身份驗證。
    • 可以控制下載進度(通過監聽 fetch 的 onprogress 事件)。
    • 靈活性高,可以根據需求進行定制。

    缺點是:

    • 代碼相對復雜。
    • 需要處理跨域問題(如果文件在不同的域名下)。

前端下載文件,這三種方法各有千秋,具體選擇哪種,取決于你的實際需求。 如果只是簡單下載同源文件,標簽 + download 屬性足夠了。 如果需要下載不同源的文件,或者需要自定義請求頭,那么 Blob 對象和 URL.createObjectURL 是更好的選擇。

下載大文件時如何優化用戶體驗?

下載大文件,最怕的就是用戶傻等,不知道下載進度。所以,優化用戶體驗的關鍵在于:

  1. 顯示下載進度

    使用 Blob 對象和 URL.createObjectURL 方法時,可以通過監聽 fetch 的 onprogress 事件來獲取下載進度。

    fetch(url, {   method: 'GET' }) .then(res => {   const contentLength = res.headers.get('content-length');   let receivedLength = 0;   const reader = res.body.getReader();    return new ReadableStream({     start(controller) {       function push() {         reader.read().then(({ done, value }) => {           if (done) {             controller.close();             return;           }           receivedLength += value.length;           // 計算下載進度           const progress = (receivedLength / contentLength * 100).toFixed(2);           console.log(`下載進度:${progress}%`);           // 更新ui顯示下載進度           updateProgressUI(progress);            controller.enqueue(value);           push();         });       }       push();     }   })   .pipeTo(new WritableStream({     write(chunk) {       // 這里可以處理下載的數據,比如寫入文件     }   }))   .then(() => {     console.log('下載完成');   }); });  function updateProgressUI(progress) {   // 更新UI顯示下載進度,比如更新進度條   document.getElementById('progress-bar').style.width = `${progress}%`; }

    這段代碼的關鍵在于使用 ReadableStream 來讀取響應數據,并在讀取過程中計算下載進度,然后更新UI顯示。

  2. 斷點續傳

    如果文件非常大,可以考慮支持斷點續傳。斷點續傳的原理是在請求頭中添加 Range 字段,告訴服務器從哪個位置開始傳輸數據。

    function downloadFileWithResume(url, filename, start) {   fetch(url, {     method: 'GET',     headers: {       'Range': `bytes=${start}-`     }   })   .then(res => res.blob())   .then(blob => {     // ... 后續處理與之前相同   }); }

    服務器也需要支持 Range 請求頭,并返回 206 Partial Content 狀態碼。

  3. 使用 Web Workers

    下載大文件可能會阻塞線程,導致頁面卡頓。可以使用 Web Workers 將下載任務放在后臺線程中執行,避免阻塞主線程。

    // 主線程 const worker = new Worker('download-worker.JS'); worker.postMessage({ url: 'path/to/your/file.pdf', filename: '自定義文件名.pdf' });  worker.onmessage = function(event) {   const data = event.data;   if (data.progress) {     // 更新UI顯示下載進度     updateProgressUI(data.progress);   } else if (data.complete) {     console.log('下載完成');   } };  // download-worker.js self.addEventListener('message', function(event) {   const { url, filename } = event.data;   downloadFile(url, filename, function(progress) {     self.postMessage({ progress: progress });   }, function() {     self.postMessage({ complete: true });   }); });  function downloadFile(url, filename, progressCallback, completeCallback) {   // ... 下載文件的代碼,并在下載過程中調用 progressCallback 更新進度   // 下載完成后調用 completeCallback }

    這種方法將下載任務放在后臺線程中執行,避免阻塞主線程,提高頁面響應速度。

如何處理下載失敗的情況?

下載文件,難免會遇到各種各樣的問題,比如網絡中斷、服務器錯誤等等。所以,我們需要處理下載失敗的情況,給用戶一個友好的提示。

  1. 監聽 fetch 的錯誤

    fetch 函數會返回一個 promise 對象,如果請求失敗,Promise 對象會 reject。我們可以使用 catch 方法來捕獲錯誤。

    fetch(url, {   method: 'GET' }) .then(res => res.blob()) .then(blob => {   // ... 下載成功的處理 }) .catch(Error => {   console.error('下載失敗:', error);   // 顯示錯誤提示   alert('下載失敗,請稍后重試'); });
  2. 檢查 http 狀態碼

    如果服務器返回的 HTTP 狀態碼不是 200,也表示下載失敗。我們可以檢查 response.ok 屬性來判斷請求是否成功。

    fetch(url, {   method: 'GET' }) .then(res => {   if (!res.ok) {     throw new Error(`HTTP 錯誤:${res.status}`);   }   return res.blob(); }) .then(blob => {   // ... 下載成功的處理 }) .catch(error => {   console.error('下載失敗:', error);   // 顯示錯誤提示   alert('下載失敗,請稍后重試'); });
  3. 重試下載

    如果下載失敗,可以嘗試重新下載。可以設置一個重試次數,如果超過重試次數仍然失敗,就放棄下載。

    function downloadFileWithRetry(url, filename, retryCount = 3) {   fetch(url, {     method: 'GET'   })   .then(res => {     if (!res.ok) {       throw new Error(`HTTP 錯誤:${res.status}`);     }     return res.blob();   })   .then(blob => {     // ... 下載成功的處理   })   .catch(error => {     console.error('下載失敗:', error);     if (retryCount > 0) {       console.log(`嘗試重新下載,剩余次數:${retryCount}`);       // 延遲一段時間后重新下載       setTimeout(() => {         downloadFileWithRetry(url, filename, retryCount - 1);       }, 1000);     } else {       // 顯示錯誤提示       alert('下載失敗,請稍后重試');     }   }); }

    這種方法在下載失敗后,會嘗試重新下載,提高下載成功率。

  4. 記錄錯誤日志

    為了方便排查問題,可以將下載失敗的錯誤信息記錄到日志中。可以使用 console.error 或者第三方的日志庫來記錄錯誤信息。

    fetch(url, {   method: 'GET' }) .then(res => res.blob()) .then(blob => {   // ... 下載成功的處理 }) .catch(error => {   console.error('下載失敗:', error);   // 記錄錯誤日志   logError('下載文件失敗', { url: url, error: error.message });   // 顯示錯誤提示   alert('下載失敗,請稍后重試'); });  function logError(message, data) {   // 將錯誤信息發送到服務器或者記錄到本地   console.log(message, data); }

    通過記錄錯誤日志,可以方便地排查問題,提高代碼質量。

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