下载文件时,若文件名含有Unicode字符,下载的文件名可能是乱码(在IE上是乱码,FF和Chrome正常),在IE上这个问题还比较常见,尤其是老版本IE(IE6/7/8)。这个问题得在Server端解决。
![](https://img.laitimes.com/img/_0nNw4CM6IyYiwiM6ICdiwiIyVGduV2QvwVe0lmdhJ3ZvwFM38CXlZHbvN3cpR2Lc1TPB10QGtWUCpEMJ9CXsxWam9CXwADNvwVZ6l2c052bm9CXUJDT1wkNhVzLcRnbvZ2LcZXUYpVd1kmYr50MZV3YyI2cKJDT29GRjBjUIF2LcRHelR3LcJzLctmch1mclRXY39jM4AzN0gzM4ATNyATM1EDMy8CX0Vmbu4GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.jpg)
分析
文件名是怎么从Server端传到浏览器的?文件名是通过Server端回复的HTTP头的Content-Disposition传过来的,比如Content-Disposition:attachment; filename=genome.jpeg就告诉浏览器,Server将要发给你的是文件,文件名为genome.jpeg。而RFC2138规定,Content-Disposition中的filename参数内容,只能是ASCII编码。
那Unicode文件名是怎么从server端传到浏览器的呢?各个浏览器的处理方法就不一样了。假设在Dropbox中有一个“测试文件.txt”,用不同的浏览器下载这个文件:
- Chrome45的content-disposition内容为
attachment;filename="%E6%B5%8B%E8%AF%95%E6%96%87%E4%BB%B6.txt";filename*=UTF-8''%E6%B5%8B%E8%AF%95%E6%96%87%E4%BB%B6.txt
- IE11的content-disposition内容为
attachment;filename=%E6%B5%8B%E8%AF%95%E6%96%87%E4%BB%B6.txt
- FF的content-disposition内容为
attachment; filename="测试文件.txt";filename*=UTF- 8''%E6%B5%8B%E8%AF%95%E6%96%87%E4%BB%B6.txt
结论
对于Unicode文件名,各个浏览器能接受的content-disposition内容不一样。但是,经实测,下面这种格式,对于IE9,Chrome,FF,都是可行的。注意content-disposition内容有三段组成。
attachment; filename="%E6%B5%8B%E8%AF%95%E6%96%87%E4%BB%B6.txt";filename*=UTF-8''%E6%B5%8B%E8%AF%95%E6%96%87%E4%BB%B6.txt
所以,对于主流浏览器,可以将文件名做URL-Encode后,送入如下字符串,作为content-position的值。(具体见这个python的Commit)
'attachment; filename="{0}";filename*=UTF-8\'\'{1}'
对于Android浏览器,还要加其它的代码支持,详见[1],其中给出了详细的方案:
- 对于IE7 & IE8
contentDisposition = "attachment;filename=" + Uri.EscapeDataString(fileName);
- 对于非Android浏览器
contentDisposition = "attachment;filename=\"" + fileName + "\"; filename*=UTF-8''" +Uri.EscapeDataString(fileName);
最后,记住,这个多浏览器兼容的问题,必须在Server端解决。
Ref:
[1] http://stackoverflow.com/questions/93551/how-to-encode-the-filename-parameter-of-content-disposition-header-in-http