下载文件中文总乱码文件名带空格总会有问题
@GetMapping("/downloadFile")
public String download(String serverFileName, HttpServletRequest request, HttpServletResponse response) throws IOException {
request.setCharacterEncoding("utf-8");
response.setContentType("application/octet-stream");
String clientFileName = fileService.getClientFileName(serverFileName);
// 对真实文件名进行百分号编码
String percentEncodedFileName = URLEncoder.encode(clientFileName, "utf-8")
.replaceAll("\\+", "%20");
// 组装contentDisposition的值
StringBuilder contentDispositionValue = new StringBuilder();
contentDispositionValue.append("attachment; filename=")
.append(percentEncodedFileName)
.append(";")
.append("filename*=")
.append("utf-8''")
.append(percentEncodedFileName);
response.setHeader("Content-disposition",
contentDispositionValue.toString());
// 将文件流写到response中
try (InputStream inputStream = fileService.getInputStream(serverFileName);
OutputStream outputStream = response.getOutputStream()
) {
IOUtils.copy(inputStream, outputStream);
}
return "OK!";
}
-
URLEncoder.encode(clientFileName, "utf-8")
方法之后,为什么还要.replaceAll("\\+", "%20")?
任何需要百分号编码的地方,都应该把空格符编码为
%20
,而URLEncoder
这个类的说明上明确标注其会将空格符转换为+
:其实这并不怪 JDK,因为它的备注里说明了其遵循的是
application/x-www-form-urlencoded
( PHP 中也有这么一个函数,也是这么个套路)所以这里我们用
.replaceAll("\\+", "%20")
把+
号处理一下,使其完全符合 [RFC 3986] 的百分号编码规范。这里为了方便说明问题,把所有操作都展现出来了。当然,你完全可以自己实现一个PercentEncoder
类,丰俭由人。 - [RFC 6266] 标准中
filename=
的value
是不需要编码的,这里的filename=
后面的 value 为什么要百分号编码?回顾 [RFC 6266] 文档,
filename
和filename*
同时出现时取后者,浏览器太老不支持新标准时取前者。目前主流的浏览器都采用自升级策略,所以大部分都支持新标准------除了老版本IE。老版本的IE对 value 的处理策略是 进行百分号解码 并使用。所以这里专门把
filename=
的value
进行百分号编码,用来兼容老版本 IE。