最近做了一个文件上传下载的功能,但是在下载的时候,出现了一点问题,文件名包含中文的时候,IE、google浏览器文件名称没有乱码,但是火狐浏览器文件名乱码,从网上找了很久都没有解决,记录一下自己解决此此问题的过程。
1、前端页面传参
location.href = "${path}/AppFileDownload.action?file_path="+file_path+"&file_name="+encodeURI(encodeURI(file_name));
此处对文件名做了编码处理,此处解释一下为什么用两次encodeURI编码:
如果只进行一次encodeURI,得到的是UTF-8形式的URL,服务器端通过request.getParameter()解码查询参数(通常是iso-8859-1)就会得到乱码。
如果进行两次encodeURI,第一次编码得到的是UTF-8形式的URL,第二次编码得到的依然是UTF-8形式的URL,但是在效果上相当于首先进行了一次UTF-8编码(此时已经全部转换为ASCII字符),再进行了一次iso-8859-1编码,因为对英文字符来说UTF-8编码和ISO-8859-1编码的效果相同。在服务器端,首先通过request.getParameter()自动进行第一次解码(可能是gb2312,gbk,utf-8,iso-8859-1等字符集,对结果无影响)得到ascii字符,然后再使用UTF-8进行第二次解码,通常使用java.net.URLDecoder("","UTF-8")方法。
两次编码两次解码的过程为:
UTF-8编码->UTF-8(iso-8859-1)编码->iso-8859-1解码->UTF-8解码,编码和解码的过程是对称的,所以不会出现乱码。
假设页面端输入的中文是一个“中”,按照下面步骤进行解码
(1)第一次encodeURI,按照utf-8方式获取字节数组变成[-28,-72-83],对字节码数组进行遍历,把每个字节转化成对应的16进制数,这样就变成了[E4,B8,AD],最后变成[�,�,�] 此时已经没有了多字节字符,全部是单字节字符。
(2)第二次encodeURI,进行编码,会把%看成一个转义字符,并不编码%以后字符,会把%编码成%.把数组最后变成[�,�,�]然后就把处理后的数据[�,�,�]发往服务器端,
当应用服务器调用getParameter方法,getParameter方法会去向应用服务器请求参数
应用服务器最初获得的就是发送来的[�,�,�],应用服务器会对这个数据进行URLdecode操作,应用服务器进行解码的这一次,不管是按照UTF-8,还是GBK,还是ISO-8859,,都能得到[�,�,�],因为都会把%解析成%.并把这个值返回给getParameter方法
(3)再用UTF-8解码一次,就得到"中"了。
如果不编码两次,当服务器自动解码的时候,假如是按照ISO-8859去解码UTF-8编码的东西,就是会出现乱码。
2、服务端处理文件名乱码问题
@Override
public String execute() throws Exception {
HttpServletRequest request = ServletActionContext.getRequest();
HttpServletResponse response = ServletActionContext.getResponse();
request.setCharacterEncoding("UTF-8");
response.setCharacterEncoding("UTF-8");
String filePath = request.getParameter("file_path");
String fileName = request.getParameter("file_name");
// 获取要传递给客户端的文件数据
ServletOutputStream outputStream = null;
byte[] bytes = FastDFSUtil.download(filePath, fileName);
// 解决浏览器中文乱码的问题
if (request.getHeader("User-Agent").toLowerCase().indexOf("firefox") > 0) {
// 火狐
//解码一次
fileName = java.net.URLDecoder.decode(fileName,"UTF-8");
BASE64Encoder base = new BASE64Encoder();
fileName = "=?utf-8?B?"+base.encode(fileName.getBytes("utf-8"))+"?=";
} else if (request.getHeader("User-Agent").toUpperCase()
.indexOf("MSIE") > 0) {
// IE浏览器
fileName = URLEncoder.encode(fileName, "UTF-8");
} else if (request.getHeader("User-Agent").toUpperCase()
.indexOf("CHROME") > 0) {
// 谷歌
fileName = new String(fileName.getBytes("UTF-8"), "ISO-8859-1");
}
// 设置响应头, 响应为下载,下载的文件名是什么
response.addHeader("Content-Disposition", "attachment; filename="+ fileName);
response.setContentType("application/octet-stream");
response.setHeader("Pragma", "public");
response.setHeader("Cache-Control", "max-age=0");
try {
outputStream = response.getOutputStream();
outputStream.write(bytes);
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
outputStream.flush();
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return null;
}