public String download(HttpServletResponse response, String fileName) {
File file = new File(filePath + '/' + fileName);
if (!file.exists()) {
return "下载文件不存在";
}
response.reset();
response.setContentType("application/octet-stream");
response.setCharacterEncoding("utf-8");
response.setContentLength((int) file.length());
response.setHeader("Content-Disposition", "attachment;filename=" + fileName);
try (BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file));) {
byte[] buff = new byte[1024];
OutputStream os = response.getOutputStream();
int i = 0;
while ((i = bis.read(buff)) != -1) {
os.write(buff, 0, i);
os.flush();
}
} catch (IOException e) {
log.error("文件下载失败:==>{}==>{}", fileName, e);
return "下载失败";
}
return "下载成功";
}
- 文件路径中可能存在恶意构造的这种相对路径:
../
需要清理。 -
ContentType
不应该滥用application/octet-stream
,应该详细的指明文件的ContentType。 -
Content-Disposition
中的filename
不能直接拼接文件名称,可能会导致乱码。 - 流复制代码冗余了,标准库自带。而且缓冲区仅1kb,太小了。
- 应该设置
Content-Length
头,客户端依赖它实现下载进度。
1 个赞
可以参考这个.
private String base = "D:\\";
public long download(HttpServletRequest request, HttpServletResponse response, String file) throws IOException {
Path path = Paths.get(base, file).normalize();
// 文件不存在,或者目标文件是目录
if (Files.notExists(path) || Files.isDirectory(path)) {
response.sendError(HttpServletResponse.SC_NOT_FOUND);
return 0;
}
// 尝试获取文件的ContentType
String mediaType = Files.probeContentType(path);
if (mediaType == null) {
// 获取失败,使用通用的二进制文件类型
mediaType = MediaType.APPLICATION_OCTET_STREAM_VALUE;
}
// Content-Type
response.setHeader(HttpHeaders.CONTENT_TYPE, mediaType);
// Content-Disposition
response.setHeader(HttpHeaders.CONTENT_DISPOSITION, ContentDisposition.attachment()
.filename(path.getFileName().toString(), StandardCharsets.UTF_8).build().toString());
// Content-Length
response.setContentLengthLong(Files.size(path));
return Files.copy(path, response.getOutputStream());
}
1 个赞