Content-Disposition文件名中的特殊字符

35
我的问题是如何在HTTP的Content-Disposition头中编码文件名参数?的副本。但是,因为那个问题很久以前就被问过了,而且还没有令人满意的答案(在我看来),所以我想再问一次。
我开发了一个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

当只使用双引号时,会出现以下问题:

  • = 在文件名中会消失
  • € 会被替换为 -

但是这样可以解决问题:

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''...会产生以下问题:

  • 文件名中多个连接在一起的空格被减少为一个
  • { 和 } 消失: "ab{}cd.txt" -> "abcd.txt"
  • 文件名在 ; 后被截断: "abc ; def.txt" -> "abc"

编辑2: 这是由于文件名长度限制。这种语法在Opera中可以使用:

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

苹果浏览器

  • € will be replaced by an invisble character (using double quotes)

    no solution that prevents that little problem
    

另一个线程中的建议(如上所述)使用

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: 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

我得到了以下结果:

  • Firefox可用
  • Chrome可用
  • IE:$ % & ( ) = ` ´ { } [ ] ² ³ @ € µ ^ ° ~ + ' # - _ . , ; ü ä ö ß 9.jpg(删除了前6个字符)。编辑2:这是因为浏览器的文件名长度限制。它开始从字符串的开头截断文件名。我没有深入研究,但看起来普通文件名可以长达200个字符,具有许多转义序列的文件名甚至更多,但少于250个。但没关系。
  • Opera:0!§ $ % & ( ) = ` ´ [] ² ³ @ € µ ^ ° ~ + ' # - _ . , ; ü ä ö ß 9.jpg(与之前一样缺少一些字符)。编辑2:我缩短了我的测试字符串,因为我怀疑Opera存在文件名长度“问题”,就像IE一样,在那里也能正常工作。
  • Safari不支持该语法。这是意料之中的。

编辑2:

到目前为止,filename*=UTF-8''filname escape sequence"语法适用于除Safari之外的所有浏览器。而唯一被Safari替换的字符是€。我想我可以接受这一点。谢谢!

编辑3:文件名长度

我注意到了一些文件名长度问题。

  • Internet Explorer:文件名可以长达147个字符。如果字符串不包含转义序列,则文件名长度为147个字符。如果包含,则文件名可能会有所变化。生成的文件名比147个字符短。但是它们不同。我使用了2个转义序列,文件名缩短了5个字符,我使用了许多转义序列,文件名仅缩短了2个字符。我找不到规律。
  • 其他浏览器似乎没有这个问题。如果文件系统能够处理,它们将保存文件。例如,我尝试使用250个字符,浏览器说我必须缩短文件名(Chrome),或者他们自己缩短到220(Opera)或210(Firefox)个字符。Opera切断了文件末尾。Safari尝试保存那个长文件名,最终没有保存,并在下载列表中写入“-1”作为文件名。

2
如果你想引起对一个旧问题的关注,你应该在上面发布悬赏。重新发布是垃圾行为。 - Jim
1
如果你想修复浏览器问题,建议与供应商沟通。这样可能会更有效。在此之前,请提供每个浏览器都能理解的文件名,为什么要让它变得更加复杂呢? - hakre
1
@juergend:从技术上讲,用户不能选择任何她想要的文件名。没有规范就不能编写代码,否则会遇到这样的问题。我尊重您愿意给用户广泛选择的意愿,但请记住,您无法满足每个人的愿望。例如文件名中的控制字符。请注意。 - hakre
这个回答对我有用。 - bronze man
显示剩余2条评论
1个回答

15

Firefox,MSIE(从版本9开始),Opera,Konq和Chrome支持;MSIE8和Safari不支持;其他支持情况未知 - RFC 5987中定义的编码。

请注意,在

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

你的欧元字符编码有误,它的Unicode代码点不是%80,修正后应该在除Safari外的所有地方正常工作(正确的编码为%e2%82%ac)。

测试用例位于:

http://greenbytes.de/tech/tc2231/#attwithfn2231utf8


1
hakre: 我建议始终使用新的RFC 5987变体,并为诸如Safari和IE版本9之前的旧版浏览器添加纯ASCII变体。另请参阅:greenbytes.de/tech/webdav/rfc6266.html#examples - Julian Reschke
1
Juergen - 你能制作一些最小化的测试用例来展示IE和Opera的问题吗?然后我可以将它们添加到我的测试套件中。谢谢。顺便说一句,注意UA过滤掉某些字符(如控制字符或路径分隔符)是完全可以的;但有趣的是看看它们以不同的方式进行过滤。 - Julian Reschke
1
hakre - 回退取决于顺序; IE8 需要先看到全 ASCII 变体。请查看 http://greenbytes.de/tech/tc2231/#attfnboth 和 http://greenbytes.de/tech/tc2231/#attfnboth2。 - Julian Reschke
@JulianReschke:我找到问题所在了,它是由于文件名长度限制造成的。在文件名中使用许多特殊字符会导致非常长的转义序列文件名。请参见上文。感谢帮助! - juergen d
@JulianReschke:请参见上面的EDIT3。 - juergen d
显示剩余6条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接