Java servlet 下载文件名特殊字符 [英] Java servlet download filename special characters

查看:32
本文介绍了Java servlet 下载文件名特殊字符的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在编写一个简单的文件下载 servlet,但我无法获得正确的文件名.尝试了现有答案中的 URLEncoding 和 MimeEncoding 文件名,但都没有奏效.

以下代码段中的 fileData 对象包含 mime 类型、byte[] 内容和文件名,至少需要 ISO-8859-2 字符集,ISO-8859-1 是不够的.

如何让浏览器正确显示下载的文件名?

这是文件名的示例:árvíztűrőtükörfúrógép.xls,结果为:árvíztqrptükörfúrógép.xls

 protected void renderMergedOutputModel(Map model, HttpServletRequest req, HttpServletResponse res) 抛出异常 {RateDocument fileData = (RateDocument) model.get("command.retval");OutputStream out = res.getOutputStream();如果(文件数据!= null){res.setContentType(fileData.getMime());String enc = "utf-8";//也尝试过:ISO-8859-2String encodingFileName = fileData.getName();//也尝试过 URLencoding 和 mime 编码这个文件名,但没有成功res.setCharacterEncoding(enc);//试过有没有这个res.setHeader("Content-Disposition", "attachment; filename=" + encodingFileName);res.setContentLength(fileData.getBody().length);out.write(fileData.getBody());} 别的 {res.setContentType("文本/html");out.write("<html><head></head><body>下载文件时出错</body></html>".getBytes(res.getCharacterEncoding()));}out.flush();}

解决方案

我找到了适用于我安装的所有浏览器(IE8、FF16、Opera12、Chrome22)的解决方案.
它基于这样一个事实,即浏览器期望文件名参数中的值,如果未指定 [不同] 编码,则该参数以浏览器本机编码进行编码.

通常浏览器的原生编码是 utf-8(FireFox、Opera、Chrome).但是IE的原生编码是Win-1250.

因此,如果我们将 value 放入文件名参数中,即根据用户的浏览器由 utf-8/win-1250 编码,它应该可以工作.至少,它对我有用.

String fileName = "árvíztűrőtükörfúrógép.xls";String userAgent = request.getHeader("user-agent");boolean isInternetExplorer = (userAgent.indexOf("MSIE") > -1);尝试 {byte[] fileNameBytes = fileName.getBytes((isInternetExplorer) ? ("windows-1250") : ("utf-8"));String dispositionFileName = "";for (byte b: fileNameBytes) dispositionFileName += (char)(b & 0xff);String disposition = "attachment; filename="" + dispositionFileName + """;response.setHeader("Content-disposition", disposition);} catch(UnsupportedEncodingException ence) {//... 处理异常 ...}

当然,这仅在上述浏览器上进行了测试,我不能 100% 保证这将始终适用于任何浏览器.

注意 #1 (@fallen):使用 URLEncoder.encode() 方法是不正确的.尽管方法的名称,它不会将字符串编码为 URL 编码,但它会编码为表单编码.(表单编码与 URL 编码非常相似,在很多情况下它会产生相同的结果.但存在一些差异.例如,空格字符"" 的编码不同:+"而不是%20")

对于正确的 URL 编码字符串,您应该使用 URI 类:

URI uri = new URI(null, null, "árvíztűrőtükörfúrógép.xls", null);System.out.println(uri.toASCIIString());

I am writing a simple file download servlet and I can't get correct filenames. Tried URLEncoding and MimeEncoding the filename as seen in existing answers, but none of them worked.

The fileData object in the following snippet contains the mime type, the byte[] content and the filename, that needs at least ISO-8859-2 charset, ISO-8859-1 is not enough.

How can I get my browser to display the downloaded filename correctly?

Here is an example of the filename: árvíztűrőtükörfúrógép.xls and it results in: árvíztqrptükörfúrógép.xls

  protected void renderMergedOutputModel(Map model, HttpServletRequest req, HttpServletResponse res) throws Exception {

    RateDocument fileData = (RateDocument) model.get("command.retval");
    OutputStream out = res.getOutputStream();
    if(fileData != null) {
        res.setContentType(fileData.getMime());
        String enc = "utf-8"; //tried also: ISO-8859-2

        String encodedFileName = fileData.getName();
            // also tried URLencoding and mime encoding this filename without success

        res.setCharacterEncoding(enc); //tried with and without this
        res.setHeader("Content-Disposition", "attachment; filename=" + encodedFileName);
        res.setContentLength(fileData.getBody().length);
        out.write(fileData.getBody());
    } else {
        res.setContentType("text/html");
        out.write("<html><head></head><body>Error downloading file</body></html>"
                .getBytes(res.getCharacterEncoding()));
    }
    out.flush();
  }

解决方案

I found out solution that works in all browsers I have installed (IE8, FF16, Opera12, Chrome22).
It's based on the fact, that browsers expect value in filename parameter, that is encoded in browsers native encoding, if no [different] encoding is specified.

Usually browser's native encoding is utf-8 (FireFox, Opera, Chrome). But IE's native encoding is Win-1250.

So if we put value into filename parametr, that is encoded by utf-8/win-1250 according to user's browser, it should work. At least, it works for me.

String fileName = "árvíztűrőtükörfúrógép.xls";

String userAgent = request.getHeader("user-agent");
boolean isInternetExplorer = (userAgent.indexOf("MSIE") > -1);

try {
    byte[] fileNameBytes = fileName.getBytes((isInternetExplorer) ? ("windows-1250") : ("utf-8"));
    String dispositionFileName = "";
    for (byte b: fileNameBytes) dispositionFileName += (char)(b & 0xff);

    String disposition = "attachment; filename="" + dispositionFileName + """;
    response.setHeader("Content-disposition", disposition);
} catch(UnsupportedEncodingException ence) {
    // ... handle exception ...
}

Of course, this is tested only on browsers mentioned above and I cannot guarante on 100% that this will work in any browser all time.

Note #1 (@fallen): It's not correct to use URLEncoder.encode() method. Despite method's name, it doesn't encode string into URL-encoding, but it does encode into form-encoding. (Form-encoding is quite similiar to URL-encoding and in a lot of cases it produces same results. But there are some differences. For example space character ' ' is encoded different: '+' instead of '%20')

For correct URL-encoded string you should use URI class:

URI uri = new URI(null, null, "árvíztűrőtükörfúrógép.xls", null);
System.out.println(uri.toASCIIString());

这篇关于Java servlet 下载文件名特殊字符的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆