JSP实现文件下载功能详解
基本原理
通过JSP动态生成HTTP响应头,设置Content-Type
和Content-Disposition
,将服务器文件以流的形式传输到客户端,核心步骤包括:
- 获取文件路径/名称
- 检查文件存在性
- 设置响应头
- 读取文件流并输出
实现步骤
步骤 | 操作说明 | 技术要点 |
---|---|---|
1 | 接收请求参数 | request.getParameter() 获取文件标识 |
2 | 文件校验 | File.exists() 检查文件存在性路径安全校验(禁止目录遍历) |
3 | 设置响应头 | response.setContentType("application/octet-stream") response.setHeader("Content-Disposition", "attachment; filename="" + fileName + """) |
4 | 文件传输 | 使用FileInputStream 读取文件通过 ServletOutputStream 输出字节流 |
代码示例
<%@ page import="java.io." %> <% // 获取文件参数(需做安全校验) String fileName = request.getParameter("file"); String filePath = application.getRealPath("/") + "downloads/" + fileName; File file = new File(filePath); // 安全校验 if(!file.exists() || fileName.contains("..")) { response.sendError(HttpServletResponse.SC_NOT_FOUND); return; } // 设置响应头 response.setContentType("application/octet-stream"); response.setHeader("Content-Disposition", "attachment; filename="" + fileName + """); response.setContentLength((int)file.length()); // 文件传输 try(InputStream in = new FileInputStream(file); OutputStream out = response.getOutputStream()) { byte[] buffer = new byte[4096]; int bytesRead; while((bytesRead = in.read(buffer)) != -1) { out.write(buffer, 0, bytesRead); } out.flush(); } catch(IOException e) { throw new ServletException("文件下载失败", e); } %>
注意事项
风险点 | 解决方案 |
---|---|
路径穿越攻击 | 参数做正则校验 使用 File.canonicalPath 校验路径 |
中文文件名乱码 | 使用URLEncoder.encode(fileName, "UTF-8") 处理 |
大文件内存溢出 | 使用缓冲区(如4KB) 配置Tomcat的 swallowAtEnd 参数 |
并发下载死锁 | 使用try-with-resources 自动管理流 |
相关问题与解答
Q1:如何处理包含中文字符的文件名?
A1:在设置Content-Disposition
时,需要对文件名进行URL编码:
String encodedName = URLEncoder.encode(fileName, "UTF-8"); response.setHeader("Content-Disposition", "attachment; filename="" + encodedName + """);
浏览器会根据编码自动解析中文文件名。
Q2:如何限制只能下载特定类型的文件?
A2:通过检查文件扩展名或MIME类型实现:
// 方法1:检查扩展名 if(!fileName.endsWith(".pdf") && !fileName.endsWith(".docx")) { response.sendError(HttpServletResponse.SC_FORBIDDEN); return; } // 方法2:检查MIME类型 String mimeType = getServletContext().getMimeType(filePath); if(!mimeType.startsWith("application/")) { response.sendError(HttpServletResponse.SC_FORBIDDEN); return; }
原创文章,发布者:酷盾叔,转转请注明出处:https://www.kd.cn/ask/75695.html