zoukankan      html  css  js  c++  java
  • Content-Disposition中filename字段的字符编码技巧[转]

    本文是关于“如何编码http包的Content-Disposition中的filename字段?”这个问题的又一次探讨。这个问题在很久之前被提出来以后,到现在仍然没有满意的答案,至少我认为是这样的,所以今天我再次把这个问题抛出来,附上我的解决办法。

    我编写了一个基于C++的CGI应用,他可以解析包含特殊字符文件名的文件,比如像这样:weird # € = { } ; filename.txt。

    似乎没有一种通用方法来搞定HTTP中的Content-Dispostion使之可以在每个浏览器中都正常工作,测试的浏览器有以下:

    •    Internet Explorer
    •    Firefox
    •    Chrome
    •    Opera
    •    Safari

    不过我倒是很乐意针对不同的浏览器用不同的办法来编码。

    下面就说说我采用的办法:

    Internet Explorer(添加双引号并且替换#和;符号):

    Content-Disposition: attachment; filename="weird %23 € = { } %3B filename.txt"

    Firefox(双引号仍然有用,无需其他改动):

    Content-Disposition: attachment; filename="weird # € = { } ; filename.txt"

    另有一种可行的替代方案:

    Content-Disposition: attachment; filename*=UTF-8''weird%20%23%20%e2%82%ac%20%3D%20%7B%20%7D%20%3B%20filename.txt

    Chrome:

    只用双引号的时候会出现下面这些问题:

    1. 文件名中的=符号会丢失
    2. €会被替换成-符号

    用这种办法就能搞定了:

    Content-Disposition: attachment; filename*=UTF-8''weird%20%23%20%e2%82%ac%20%3D%20%7B%20%7D%20%3B%20filename.txt

    Opera:

    用双引号或者语法:filename*=UTF-8”,会产生下面这些问题:

    1. 文件名中的多个连续空格只剩下一个
    2. 成对的{}丢失:”ab{}cd.txt” -> “abcd.txt”
    3. 文件名中的分号会截断后面的字符:”abc ; def.txt” -> “abc”

    这是由于文件名长度限制造成的,下面的例子可以在Opera中工作:

    Content-Disposition: attachment; filename*=UTF-8''weird%20%23%20%e2%82%ac%20%3D%20%7B%20%7D%20%3B%20filename.txt

    Safari:

    如果用双引号,€符号会被替换成不可见字符,很遗憾没有合适的办法来解决这个小问题。

    但是从上面提到的那个问题原文中得到一个可以参考的办法:

    Content-Disposition: attachment; filename*=UTF-8''weird%20%23%20%80%20%3D%20%7B%20%7D%20%3B%20filename.txt

    但是这个方案对我来说没有用,这些转义字符没办法被正确的还原所以浏览器尝试了用cgi应用的名称来保存文件。造成这个问题的原因是我采用的编码方式不正确。我没有按照RFC 5987的原则来编码。不过Safari也同样没有采用这种编码方式。所以只能说€字符的编码方法暂时无解了。

    顺便提一下,一个UTF-8编码转换器:http://www.rishida.net/tools/conversion/

    上文提到的所有测试均用了当前最新版本的浏览器:

    •     Firefox 7
    •     Internet Explorer 9
    •     Chrome 15
    •    Opera 11.5
    •     Safari 5.1

    PS:我尝试过键盘上所有的特殊字符,但是被我提到的是那些会造成问题的字符。

    我顺便尝试了下在文件名中同时包含所有可能出现的特殊字符,测试结果和上面提到的不太一样:

    完整的测试字符串:

    0!§ $%&()=`´{}  []²³@€µ^°~+' # - _ . , ; ü ä ö ß 9.jpg

    编码后:

    0%20%21%20%C2%A7%20%24%20%25%20%26%20%28%20%29%20%3D%20%60%20%C2%B4%20%7B%20%7D%20%20%20%20%5B%20%5D%20%C2%B2%20%C2%B3%20%40%20%E2%82%AC%20%C2%B5%20%5E%20%C2%B0%20~%20%2B%20%27%20%23%20-%20_%20.%20%2C%20%3B%20%C3%BC%20%C3%A4%20%C3%B6%20%C3%9F%209.jpg

    Content-Disposition用这种方式来写:

    Content-Disposition: attachment; filename*=UTF-8''0%20%21%20%C2%A7%20%24%20%25%20%26%20%28%20%29%20%3D%20%60%20%C2%B4%20%7B%20%7D%20%20%20%20%5B%20%5D%20%C2%B2%20%C2%B3%20%40%20%E2%82%AC%20%C2%B5%20%5E%20%C2%B0%20~%20%2B%20%27%20%23%20-%20_%20.%20%2C%20%3B%20%C3%BC%20%C3%A4%20%C3%B6%20%C3%9F%209.jpg

    得到了如下测试结果:

    火狐可以正常工作

    Chrome可以正常工作

    IE显示:$ % & ( ) = ` ´ { } [ ] ² ³ @ € µ ^ ° ~ + ‘ # – _ . , ; ü ä ö ß 9.jpg 丢失了头6个字符

    解释下:出现这个问题是因为浏览器对文件名字符长度的限制造成的:从字符串的开头舍弃一些字符。我没有深入挖掘这一点,不过正常的文件名大约可以长达大概200个字符,那些文件名包含许多转义字符序列的长度甚至可以更多,但是不超过250个字符。所以说这个其实没啥问题。

    Opera:0 ! § $ % & ( ) = ` ´ [ ] ² ³ @ € µ ^ ° ~ + ‘ # – _ . , ; ü ä ö ß 9.jpg 和IE中的那样也丢失了一些字符。

    说明:我缩减过我的测试字符串,因为我怀疑Opera中也有像IE那样的长度限制问题。

    Safari中这种编码无法正常使用。

    测试到现在说明一个事实:形如“filename*=UTF-8”filname escape sequence”这样的语法可在除了safari外的其他浏览器中正常工作。但是在Safari中用这种方法也只有€会被替换掉。所以这个问题不大。

    关于文件名长度:

    测试中发现了一些文件名长度的问题。

    在Internet Explorer中:文件名长度最多可以长达147个字符。如果字符串中没有出现转移字符的话,这就是文件名的总长度了。如果字符串中出现了转移字符,情况就有些变化。最终的文件名长度小于147个字符。但是规则有点奇怪,我找不出一个准确的规则。如果我用了两个转义字符,文件名缩短了5个字符长度,但是我用很多转义字符的话文件名最终只缩短了两个字符。

    其他浏览器没有这个长度限制问题。只要系统能够处理这个文件,它就能顺利保存这个文件。我测试了下250个字符长度的文件名,chrome提示我要缩减文件名长度,opera会自动缩减到220个字符,火狐自动缩减为210个字符。Opera会从文件名末尾开始缩减。Safari尝试保存那么长的文件名,但是处理失败无法保存,同时在下载列表的文件名中会显示成-1。

  • 相关阅读:
    Rabbitmq 性能测试
    B+树图文详解
    图的概念和存储(邻接矩阵,邻接表)
    WebApi系列文章
    Asp.Net MVC项目集成Swagger
    正则表达式匹配两个特殊字符中间的内容
    数学常数e的含义
    十大排序算法总结
    C#集合类型大揭秘
    深入System.Web.Caching命名空间 教你Hold住缓存管理(三)
  • 原文地址:https://www.cnblogs.com/feb9903/p/4701966.html
Copyright © 2011-2022 走看看