项目场景:
自己开发的文件服务项目在使用时测试反馈在下载文件时,文件名包含逗号时下载失败,无法跳转到下载链接页面。
项目使用springboot开发,文件的上传基于SpringMVC的表单文件上传。但是下载时由于需要下载原文件名,并且需要从数据库中查询到附件的中文名称再赋值给响应头,因此采用了流的方式返回文件。
问题描述
文件名如下,不得不吐槽真是清新脱俗而又不失温文尔雅的文件名(tmd)
副本AAB,AIGJ,AIPG,BCAP,BESP,BHL,BKG,BOA,CPM--CPM.xlsx (21.08K)
错误信息:
下载文件报错“:org.apache.catalina.connector.ClientAbortException: java.io.IOException: 远程主机强迫关闭了一个现有的连接。
在跳转下载链接时页面响应如下
原因分析:
测试了一下中文逗号,可以正常下载。问题就很清晰了,附件下载时因文件名中含有英文逗号
,被浏览器(本次使用chrome)中断,导致下载失败,页面显示网页不可用
解决方案:
设置响应头添加引号
查到是谷歌浏览器的一个bug,因此我们设置响应头时,对于filename加上引号处理
设置响应头Content-Disposition中实际效果如:content-disposition=attachment;fileName=“原文件名称”
response.setHeader("Content-Disposition", "attachment;filename=\"" + FileUtil.encodeChineseDownloadFileName(request, realFileName) + "\"");
代码如下:
关于文件名下载乱码的解决方案
FileUtil.encodeChineseDownloadFileName(request, realFileName)
/**
* 浏览器下载时文件名乱码问题解决
*
* @param request
* @param pFileName 文件名
* @return
* @throws UnsupportedEncodingException
*/
public static String encodeChineseDownloadFileName(HttpServletRequest request, String pFileName) throws UnsupportedEncodingException {
String[] IE_BROWSER_SIGNALS = {"MSIE", "Trident", "Edge"};
String FIREFOX = "Firefox";
boolean isMSIE = false;
String userAgent = request.getHeader("User-Agent");
if (StringUtils.isBlank(userAgent)) {
userAgent = request.getHeader("USER-AGENT");
}
for (String signal : IE_BROWSER_SIGNALS) {
if (StringUtils.isNotBlank(userAgent) && userAgent.contains(signal)) {
isMSIE = true;
}
}
//返回的文件名
String filename;
if (isMSIE) {
//IE浏览器的乱码问题解决
filename = URLEncoder.encode(pFileName, "UTF-8");
filename = StringUtils.replace(filename, "+", "%20");
} else if (StringUtils.contains(userAgent, FIREFOX)) {
filename = "=?UTF-8?B?" + (new String(org.apache.commons.codec.binary.Base64.encodeBase64(pFileName.getBytes("UTF-8")))) + "?=";
} else {
//万能乱码问题解决
filename = new String(pFileName.getBytes("UTF-8"), "ISO-8859-1");
}
return filename;
}