下载文件中的UTF-8编码名称

31

我正试图让用户下载具有日语名称的Excel文件。它似乎仅适用于IE 8,而其他IE和Firefox则无法工作。请建议我如何处理。

String fileName = dateString+"_マイページ情報.xls";
byte[] data = writer.getData();
response.setContentType("application/ms-excel");
response.setContentLength(data.length);
response.setHeader("Expires:", "0"); // eliminates browser caching
response.setHeader("Content-Disposition","attachment; filename="+URLEncoder.encode(fileName));
6个回答

46

我按照以下方式解决了它。

fileName = dateString+"_マイページ情報.xls"; 
fileName = URLEncoder.encode(fileName,"UTF-8"); 
try {
        response.setContentType("application/ms-excel; charset=UTF-8");
        response.setCharacterEncoding("UTF-8");
        if(browserType.equals("IE")||browserType.equals("Chrome"))
            response.setHeader("Content-Disposition","attachment; filename="+fileName);
        if(browserType.endsWith("Firefox"))
            response.setHeader("Content-Disposition","attachment; filename*=UTF-8''"+fileName);
    } catch (Exception e1) {
        // TODO Auto-generated catch block
        e1.printStackTrace();
    }

1
@zawhtut,你用什么代码获取浏览器类型? - Mahmoud Saleh
1
request.getHeader("User-Agent"); 我想是获取用户代理。我已经很久没有发布这个答案了,现在记不太清楚了。 - zawhtut
2
这篇博客文章在解决此类问题时非常有帮助http://blogs.msdn.com/b/ieinternals/archive/2010/06/07/content-disposition-attachment-and-international-unicode-characters.aspx并且了解浏览器详细信息http://www.fromdev.com/2009/06/dealing-with-different-client-browsers.html - rakeeee
这个问题最常见的原因之一是文件名和文件类型之间存在空格,特别是在IE浏览器中。 - Amir Amiri
URLEncoder.encode(fileName,"UTF-8"); 解决了我的问题。我遇到了文件名字符问题,尝试了所有更改编码的方法,但只有这段代码解决了我的问题。 - fatih yavuz
显示剩余2条评论

11

使用方法setCharacterEncoding

设置发送到客户端的响应的字符编码(MIME字符集),例如UTF-8。如果字符编码已经通过setContentType(java.lang.String)或setLocale(java.util.Locale)设置,则此方法将覆盖它。使用text/html字符串调用setContentType(java.lang.String)并使用UTF-8字符串调用此方法等效于使用text/html; charset=UTF-8字符串调用setContentType。

可以多次调用此方法以更改字符编码。 如果在调用getWriter或提交响应后调用此方法,则此方法无效。

请按照以下方式修改您的代码:

response.setContentType("application/ms-excel; charset=UTF-8");
response.setCharacterEncoding("UTF-8");
response.setHeader("Content-Disposition","attachment; filename="+URLEncoder.encode(fileName, "UTF-8"));

这在Chrome上运作良好,但在Safari和Firefox上对我来说并没有用。两者均根据其URL编码的“文件名”属性命名了文件。 - yngwietiger
1
@yngwietiger:尝试在Firefox中使用以下代码 - response.setHeader("Content-Disposition","attachment; filename*=UTF-8''"+fileName); - Ankur Lathi

5

1
给定的链接已失效,请改用https://docs.oracle.com/javase/7/docs/api/java/net/URLEncoder.html#encode(java.lang.String,%20java.lang.String)。 - jack_07

3
这是我所做的事情,并且在我尝试的所有浏览器中都有效(Chrome,Firefox和Safari)。此外,我没有编写任何特定于浏览器的代码。
根据此链接:http://blogs.msdn.com/b/ieinternals/archive/2010/06/07/content-disposition-attachment-and-international-unicode-characters.aspx

所有浏览器都将尝试从URL的路径组件中推导出文件名。

因此,如果浏览器请求以文件名结尾的URL,则会正确命名该文件。这似乎对所有浏览器都适用。 在我的个人情况下,客户端不知道要下载的文件名。我们的系统基于ID获取文件。例如:
/api/file/download/<file_id>

所以,我的做法是让API查找文件名(我们将其存储在数据库中,按file_id),对其进行URL编码,并重定向到第二个包含文件名的API。例如:

/api/file/download/<file_id>/<url-encoded filename>

然后,第二个API将使用file_id查找并流式传输文件内容,浏览器将使用文件名部分来命名下载的文件。
注意:第二个API忽略文件名(不需要它)。它还将Content-Disposition头设置为仅“attachment;”(不要设置文件名。让浏览器从URL获取它)。

1
听起来你已经很棒了,但是对于其他读者的提示,一定要非常小心地将用户输入(例如这里的URL编码文件名)包含在服务器上使用的文件路径中。这会打开路径遍历攻击的大门。相反,使用文件ID,并将实际文件名存储在数据库中;或者建立一个安全的文件名模式,并根据该模式验证用户输入。 - erickson

1
下面的代码运行良好。
String fileName = URLEncoder.encode(fileName, "UTF-8");
response.setHeader("Content-Disposition","attachment; filename="+fileName );

0
无需设置setCharacterEncoding之类的,只需要添加下面这行代码就可以了,它可以正常工作。
String fileName = URLEncoder.encode(fileName, "UTF-8");
response.setHeader("Content-Disposition","attachment; filename="+fileName );

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接