下载文件时文件名乱码问题

1.问题分析

  • 实现浏览器客户端下载文件功能时,中文文件名出现乱码无法正常显示的情况。

2.原因分析

  • 首先HTTP协议中要求传输的header内容必须是ISO8859-1编码,当我们在代码中设置request和response编码格式为UTF-8后,就需要将接收到的中文参数值转换成ISO8859-1编码格式。

  • 下面html代码中链接标签中设置url的filename参数,对于filename=头像.jpg ,就需要转换编码格式。

    1
    2
    <a href="/test/ServletDownload?filename=avatar.jpg">下载图片</a>
    <a href="/test/ServletDownload?filename=头像.jpg">下载图片</a>

3.解决

  • filename = new String(filename.getBytes(“UTF-8”), “ISO8859-1”)

    因为ISO8859-1没有中文字符集,所以先获取到filename的UTF-8编码格式后,再将其转换成ISO8859-1格式。这些字符传递到浏览器后,浏览器会通过相反的方式String filename= new String(filename.getBytes(“ISO8859-1”),”UTF-8”)来得到正确的中文汉字,这样就既保证了遵守协议规定、也支持中文。

  • 如果直接ilename.getBytes(“ISO8859-1”),是不能正确转换的,因为ISO8859-1无法直接编码中文,所以更加无法还原。

4.文件下载实现代码

download.html

1
2
3
4
5
6
7
8
9
10
11
12
13
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>下载文件</title>
</head>
<body>
<!--指向servlet,传递资源名称filename-->
<a href="/test/ServletDownload?filename=avatar.jpg">下载图片</a>
<a href="/test/ServletDownload?filename=头像.jpg">下载图片</a>
<a href="/test/ServletDownload?filename=c.txt">下载txt</a>
</body>
</html>

ServletDownload.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
@WebServlet("/ServletDownload")
public class ServletDownload extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
/*
* 页面显示超链接
* 点击超链接后弹出下载提示框
* 完成图片文件下载
* */
request.setCharacterEncoding("UTF-8");
//1.获取文件名称,找到文件服务器路径
String filename = request.getParameter("filename");
ServletContext context = this.getServletContext();
String realPath = context.getRealPath("/img/" + filename);

//2.使用字节输入流加载文件进内存
FileInputStream fs = new FileInputStream(realPath);
//3.指定response的header content-disposition:attachment;filenamexxx
String mimeType = context.getMimeType(filename);//获取文件类型
response.setContentType(mimeType);

//tomcat默认编码 ISO8859-1,将获取到的UTF-8格式转换成ISO8859-1格式,然后在浏览器端或自动还原
if (request.getHeader("User-Agent").toLowerCase().indexOf("firefox") > 0) {
filename = new String(filename.getBytes("UTF-8"), "ISO8859-1"); // firefox浏览器
} else if (request.getHeader("User-Agent").toUpperCase().indexOf("MSIE") > 0) {
filename = URLEncoder.encode(filename, "UTF-8");// IE浏览器
}else if (request.getHeader("User-Agent").toUpperCase().indexOf("CHROME") > 0) {
filename = new String(filename.getBytes("UTF-8"), "ISO8859-1");// 谷歌
}

response.setHeader("content-disposition","attachment;filename="+filename);
//4.将输入流的数据写出到response输出流
ServletOutputStream outputStream = response.getOutputStream();
byte[] bytes = new byte[1024 * 8];
int len = 0;
while((len = fs.read(bytes)) != -1){
outputStream.write(bytes,0,len);
}
fs.close();
}

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request, response);
}
}