JavaScript 與 Blob 下載檔案最佳實踐
在現代網頁開發中,下載檔案(如 PDF、圖片、Excel 等)時,常見的最佳做法如下:
1. 使用 fetch + response.blob()(自動解析 Content-Type)
fetch('<PDF URL>')
.then(response => response.blob())
.then(blob => {
const url = window.URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = '<PDF filename>.pdf';
a.click();
window.URL.revokeObjectURL(url);
});
- 優點:簡潔,fetch 會自動根據 HTTP Content-Type 產生正確的 Blob 物件。
- 適用於大多數靜態檔案、API 回傳二進位內容。
2. 使用 fetch + response.arrayBuffer() + new Blob()(自訂 MIME 類型)
fetch('<PDF URL>')
.then(response => response.arrayBuffer())
.then(arrayBuffer => {
const blob = new Blob([arrayBuffer], { type: 'application/pdf' });
const url = window.URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = '<PDF filename>.pdf';
a.click();
window.URL.revokeObjectURL(url);
});
- 優點:可自訂 MIME 類型,適合 API 未正確回傳 Content-Type 時。
- 適用於需強制指定檔案格式的場景。
3. 下載其他格式(如圖片、Excel、CSV)
只需將 type
改為對應格式即可:
const blob = new Blob([arrayBuffer], { type: 'image/png' });
// 或 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' (Excel)
4. 下載大檔案注意事項
- 建議加上 loading UI,避免用戶誤以為無反應。
- 可用 async/await 寫法提升可讀性。
- 下載完成後務必釋放 URL,避免記憶體洩漏。
5. 進階:支援 IE11(舊瀏覽器)
if (window.navigator && window.navigator.msSaveOrOpenBlob) {
window.navigator.msSaveOrOpenBlob(blob, '<PDF filename>.pdf');
} else {
// ...如上 createObjectURL 寫法
}
常見問題(FAQ)
Q1:為什麼要手動釋放 createObjectURL? A:每次呼叫 createObjectURL 都會佔用瀏覽器記憶體,若未釋放,長時間操作會造成記憶體洩漏。
Q2:如何動態產生檔名? A:可根據 API 回傳 header 或自訂規則設定 a.download,例如:
a.download = `report_${Date.now()}.pdf`;
Q3:下載後檔案損毀? A:請確認 fetch 沒有被 CORS、權限或 Content-Type 設定影響,並確保 arrayBuffer/Blob 內容正確。
Q4:如何下載非 PDF 檔案? A:只需調整 Blob 的 type 參數與下載副檔名即可。
延伸閱讀: