Servlet关于下载时中文名附件的一些问题?

Servlet技术在下载中文名称附件的时候都需要对文件名进行重新编码
例如以下这种办法:

if (agent.contains("MSIE")) {
        // IE浏览器
        filename = URLEncoder.encode(filename, "utf-8");
        filename = filename.replace("+", " ");
} else if (agent.contains("Firefox")) {
        // 火狐浏览器
BASE64Encoder base64Encoder = new BASE64Encoder();
        filename = "=?utf-8?B?"
                + base64Encoder.encode(filename.getBytes("utf-8")) + "?=";
} else {
        // 其它浏览器
        filename = URLEncoder.encode(filename, "utf-8");                
}

其中agent就是请求头User-Agent的值

一直这么用,但是有几个问题一直不明白
1.为什么要用URLEncoder.encode(filename, "utf-8");编码成application/x-www-form-urlencoded MIME 格式?我整个web应用环境都是UTF-8,为什么还要用UTF-8进行编码?

2.application/x-www-form-urlencoded MIME 格式这个不是客户端向服务器请求的格式么?为什么服务器响应的时候也要用这种格式?

3.浏览器到底能解析什么编码呢?我看到使用new String(fileName1.getBytes(“UTF-8”),”ISO8859-1”);这种方法在谷歌,火狐也可以进行中文文件名的解析。没有方法通知浏览器根据某种编码进行解码么?

阅读 2.7k
1 个回答

主要是这个附件中文文件名没有标准规定, 不同浏览器有不同的怪癖, 也就是需要逐个适配了.

使用 Content-Disposition头时, 没有单一可行的方法来编码非 ASCII 名称。浏览器兼容性很乱

使用UTF-8 的理论上正确的语法 Content-Disposition 非常奇怪:( filename*=UTF-8''foo%c3%a4是的,这是一个星号,除了中间的空单引号外没有引号)

这个 Header 有点不太标准(HTTP / 1.1规范承认它的存在,但不要求客户端支持它)。

有一个简单且非常强大的替代方法:使用包含所需文件名的URL

如果最后一个斜杠之后的名称是您想要的名称,则不需要任何额外的 Header!

这个技巧有效:

/real_script.php/fake_filename.doc

如果您的服务器支持URL重写(例如mod_rewrite在Apache中),那么您可以完全隐藏脚本部分。

URL中的字符应为UTF-8,逐字节urlencoded:

/mot%C3%B6rhead   # motörhead

以前的一个函数示例

private String codedFileName(String userAgent, String filename, String encoding)  
        throws UnsupportedEncodingException {  
  
    String new_filename = URLEncoder.encode(filename, encoding);  
    // 如果没有UA,则默认使用IE的方式进行编码,因为毕竟IE还是占多数的  
    String rtn = "=\"" + new_filename + "\"";  
    if (userAgent != null) {  
        userAgent = userAgent.toLowerCase();  
        // IE浏览器,只能采用URLEncoder编码  
        if (userAgent.indexOf("msie") != -1) {  
            rtn = "=\"" + new_filename + "\"";  
        }  
        // Opera浏览器只能采用filename*  
        else if (userAgent.indexOf("opera") != -1) {  
            rtn = "*=UTF-8''" + new_filename;  
        }  
        // Safari浏览器,只能采用ISO编码的中文输出  
        else if (userAgent.indexOf("safari") != -1) {  
            rtn = "=\""  
                    + new String(filename.getBytes(encoding), "ISO8859-1")  
                    + "\"";  
        }  
        // Chrome浏览器,只能采用MimeUtility编码或ISO编码的中文输出  
        else if (userAgent.indexOf("applewebkit") != -1) {  
            new_filename = MimeUtility.encodeText(filename, "UTF8", "B");  
            rtn = "=\"" + new_filename + "\"";  
        }  
        // FireFox浏览器,可以使用MimeUtility或filename*或ISO编码的中文输出  
        else if (userAgent.indexOf("mozilla") != -1) {  
            rtn = "*=UTF-8''" + new_filename;  
        }  
    }  
  
    return rtn;  
}  

参考:
https://stackoverflow.com/que...

推荐问题
宣传栏