Tomcat 虛擬目錄下的檔案(如 PDF、圖片、文字檔)預設會被瀏覽器直接開啟而非下載。解決方法是於 Servlet/Controller 中設定回應標頭 Content-Disposition: attachment。
@GetMapping("/download")
public void download(HttpServletRequest request, HttpServletResponse response) throws IOException {
String filePath = "/var/www/files/report.pdf"; // 實體路徑
File file = new File(filePath);
if (!file.exists()) {
response.sendError(HttpServletResponse.SC_NOT_FOUND);
return;
}
// 關鍵標頭:強制下載並指定檔名
response.setHeader("Content-Disposition", "attachment; filename=\"" + file.getName() + "\"");
response.setContentType("application/octet-stream"); // 通用二進位流
response.setContentLengthLong(file.length());
try (FileInputStream fis = new FileInputStream(file);
OutputStream os = response.getOutputStream()) {
byte[] buffer = new byte[8192];
int len;
while ((len = fis.read(buffer)) != -1) {
os.write(buffer, 0, len);
}
os.flush();
}
}
Content-Disposition: attachment 告訴瀏覽器「此內容為附件,請下載」。filename="..." 指定下載時的預設檔名(需 URL 編碼處理中文)。application/octet-stream 確保瀏覽器不嘗試解析內容。String encodedName = URLEncoder.encode(file.getName(), StandardCharsets.UTF_8)
.replaceAll("\\+", "%20");
response.setHeader("Content-Disposition", "attachment; filename*=UTF-8''" + encodedName);
此方式符合 RFC 5987,支援現代瀏覽器正確顯示中文檔名。
若檔案為靜態資源,建議由前端反向代理(Nginx)直接服務,並加上 add_header Content-Disposition "attachment";,效能更佳且減輕 Java 進程負擔。