前端勾選多個文件點擊下載,後端使用 HttpServletResponse 直接輸出流。無論是 JS 循環調用下載接口,還是後端循環寫入 response,**瀏覽器最終只能下載到一個文件**(通常是最後一個或第一個)。
HTTP 協議中單個 Response 只能攜帶一個文件流,且瀏覽器對同一 URL 的多次快速請求會被合併/覆蓋,導致無法彈出多個「另存為」對話框。
流程:前端傳遞文件 ID 集合 → 後端查詢文件 → 壓縮成 ZIP → 設置 Content-Disposition: attachment; filename="files.zip" → 單次輸出。
@PostMapping("/download/batch")
public void batchDownload(@RequestBody List<Long> ids, HttpServletResponse resp) throws IOException {
try (ZipOutputStream zos = new ZipOutputStream(resp.getOutputStream())) {
resp.setContentType("application/zip");
resp.setHeader("Content-Disposition", "attachment; filename=download_" + System.currentTimeMillis() + ".zip");
for (Long id : ids) {
File file = fileService.getFile(id);
try (FileInputStream fis = new FileInputStream(file)) {
zos.putNextEntry(new ZipEntry(file.getName()));
IOUtils.copy(fis, zos);
zos.closeEntry();
}
}
}
}
優點:用戶體驗好(單次下載)、流量可控、支持大文件斷點續傳擴展。
注意:大量/大文件打包需異步預生成 ZIP 提供下載鏈接,避免請求超時。
window.open 循環打開多標籤下載fileIds.forEach(id => {
window.open(`/download/single?id=${id}`, '_blank');
});
缺點:瀏覽器攔截彈窗、用戶需逐個確認保存路徑、並發連接數限制、無法統一進度提示。**不推薦用於生產環境**。
**「打包 ZIP 下載」是工業級標準做法**,兼顧用戶體驗與服務端性能。若文件極大或極多,請採用「異步生成 ZIP + 輪詢/下載中心」模式。