中文名文件下载浏览器兼容处理

前言

文件下载功能中的文件名处理,这又是个老生长谈的问题了,网络上也有各类解决方式,但可能因为各自项目语言以及编码不一样致使多数方案都不尽如人意,最近又遇到这个问题,姑且根据本身的环境和编码总结一下java

后续观点都是基于以下环境chrome

  • 服务端语言:JAVA
  • 项目编码:GBK
  • 应用服务器Resin 3.1

分析

Firefox会截断空格问题

在Firefox下,若是文件名中有空格,那么空格后面部分的文字会被浏览器截取掉,客户端获取不到完整的文件名浏览器

解决方案:服务器

  1. 将文件名使用双引号包裹起来
  2. 使用 MimeUtility.encodeWord(filename)方法,将其编码为“=?gb2312?B?xxxxxxxx?=”格式,其中的空格会被编码掉,而且Firefox能够识别该格式将其还原为原始的文件名

IE6下请求头长度有限制,文件名长度只能在150字节左右

通过测试,IE6下当要下载的文件名长度超过150字节后,超过部分会被浏览器截取掉(为了保证扩展名完整,浏览器会从前面截取),而且若是是中文还有可能乱码(应该是因为编码后再截取后不能再次还原为中文字符),这个是IE6自身的机制,所以咱们只能考虑使用较短的文件名或者本身使用代码合理将其截取网络

关于乱码

这一块我也不是理解的十分透彻,就个人理解简单分析一下:app

首先,你们都知道中文是多字节字符,因为计算机的基本存储单元是字节(byte),而一个byte显然不可以表示包括中文在内的全部字符,所以中文、日文等等语言在存储时都会被编码为多个字节存储到计算机中,而后显示时在相应解码显示便可。测试

而后,网络传输的单位也是字节,所以java中的字符串在传输以前若是不进行手工编码那么会被默认按照操做系统的编码格式进行编码,到客户端再按照默认格式解码,若是都是中文环境一般没有问题,可是若是两边的默认编码不一致就比较容易致使编码,所以仍是建议手动指定特定的编码和解码格式。编码

而对于文件下载,客户端不一样浏览器识别的编码也不一样,可是基本上都识别UTF-8编码以及ISO-8859-1编码,后者firefox不能识别,而且若是文件名不是全中文还会致使被截断,所以我仍是选择采用UTF-8编码spa

最后,贴上代码

因为其它功能都被拆分出去了,就不贴了,核心部分代码都在这里。操作系统

下面的代码在IE6-九、firefox、chrome测试均可以正常下载

String us = request.getHeader("user-Agent");
if(ua!=null){
    ua = ua.toLowerCase();
    //IE6截取文件名避免乱码
    if(ua.contains("msie 6")){
        //文件名中有空格,encode后会变成+,为让其正确显示空格将其替换为%20
     //getSubStr方法是根据字节数截取长度超过150字节后的字符 filename = URLEncoder.encode(getSubStr(filename),"utf-8").replaceAll("\\+","20%"); }else if(ua.contains("firefox")){ //编码成 =?gb2312?B?xxxxxxxx?=的格式,firefox支持这种格式,这里尽可能指定编码类型,不然可能解析不了 filename = MimeUtility.encodeWord(filename,"utf-8","B");
response.setHeader("Content-disposition", "attachment; filename=\"+filename+\"");
    }else{
 filename = URLEncoder.encode(filename,"utf-8").replaceAll("\\+","20%"); } } response.setContentType("application/x-download;"); response.addHeader("Content-Disposition",filename) OutputStream out = response.getOutputStream(); out.write(contents); out.flush()

 

参考资料:http://stackoverflow.com/questions/93551/how-to-encode-the-filename-parameter-of-content-disposition-header-in-http