想要强制下载资源而不是直接在Web浏览器中呈现资源的Web应用程序在表单的HTTP响应中发出 Content-Disposition
标头:
Content-Disposition: attachment; filename=FILENAME
filename
参数可用于建议浏览器下载资源的文件的名称 . 但是,RFC 2183(Content-Disposition)在section 2.3(文件名参数)中声明文件名只能使用US-ASCII字符:
当前[RFC 2045]语法将参数值(以及因此内容处理文件名)限制为US-ASCII . 我们认识到允许在文件名中使用任意字符集的巨大愿望,但是定义必要的机制超出了本文档的范围 .
然而,有经验证据表明,当今大多数流行的Web浏览器似乎都允许非US-ASCII字符(缺乏标准)对编码方案和文件名的字符集规范不同意 . 问题是,如果文件名“naïvefile”(没有引号,第三个字母是U 00EF)需要编码到Content-Disposition Headers 中,那么流行浏览器采用的各种方案和编码是什么?
出于这个问题的目的,流行的浏览器是:
-
Firefox
-
Internet Explorer
-
Safari
-
谷歌浏览器
-
歌剧
17 回答
有人对此进行了讨论,包括浏览器测试和向后兼容性的链接,提议RFC 5987,"Character Set and Language Encoding for Hypertext Transfer Protocol (HTTP) Header Field Parameters."
RFC 2183表示此类标头应根据RFC 2184进行编码,RFC 2231已被上述RFC草案覆盖RFC 2231 .
我知道这是一个老帖子,但它仍然非常相关 . 我发现现代浏览器支持rfc5987,它允许utf-8编码,百分比编码(url编码) . 然后Naïvefile.txt变成:
Safari(5)不支持此功能 . 相反,您应该使用直接在utf-8编码标头中编写文件名的Safari标准:
IE8及更早版本也不支持它,你需要使用utf-8编码的IE标准,百分比编码:
在ASP.Net中,我使用以下代码:
我使用IE7,IE8,IE9,Chrome 13,Opera 11,FF5,Safari 5测试了上述内容 .
Update 2013年11月:
这是我目前使用的代码 . 我仍然需要支持IE8,所以我无法摆脱第一部分 . 事实证明Android上的浏览器使用内置的Android下载管理器,它无法以标准方式可靠地解析文件名 .
以上现在在IE7-11,Chrome 32,Opera 12,FF25,Safari 6中测试,使用此文件名下载:你好abcABCæøåÆØÅäöüïëêîâéíáóúýñ½§!#¤%&()=`@£$€{[]}'¨^ 〜'-_,; . TXT
在IE7上,它适用于某些字符但不是全部 . 但是谁现在关心IE7呢?
这是我用来为Android生成安全文件名的函数 . 请注意,我不知道Android上支持哪些字符,但我已经测试了这些字符的确有效:
@TomZ:我在IE7和IE8中测试过,结果发现我不需要转义撇号(') . 你有失败的例子吗?
@Dave Van den Eynde:根据RFC6266将两个文件名组合在一行上,除了Android和IE7 8之外,我已更新代码以反映这一点 . 感谢您的建议 .
@Thilo:不知道GoodReader或任何其他非浏览器 . 使用Android方法可能会有一些运气 .
@Alex Zhukovskiy:我不知道为什么,但正如Connect所讨论的那样,它看起来效果不是很好 .
在
Content-Disposition
中没有可互操作的方式来编码非ASCII名称 . Browser compatibility is a mess .theoretically correct syntax在
Content-Disposition
中使用UTF-8非常奇怪:filename*=UTF-8''foo%c3%a4
(是的,这是一个星号,没有引号,除了中间的空单引号)这个 Headers 有点不太标准(HTTP/1.1 spec acknowledges its existence,但不要求客户支持它) .
有一个简单而强大的替代方案: use a URL that contains the filename you want .
当最后一个斜杠后面的名称是你想要的名字时,你不需要任何额外的 Headers !
这个技巧有效:
如果您的服务器支持URL重写(例如Apache中的
mod_rewrite
),那么您可以完全隐藏脚本部分 .URL中的字符应为UTF-8,逐字节urlencoded:
RFC 6266描述了“在超文本中使用内容处置 Headers 字段”传输协议(HTTP)“ . 引用:
并在他们的examples section:
在Appendix D中,还有一长串建议可以提高互操作性 . 它也指向a site which compares implementations . 适用于常见文件名的当前全通测试包括:
attwithisofnplain:带有双引号且无编码的普通ISO-8859-1文件名 . 这需要一个文件名,该文件名都是ISO-8859-1,并且不包含百分号,至少不在十六进制数字前面 .
attfnboth:上述顺序中的两个参数 . 应该适用于大多数浏览器上的大多数文件名,尽管IE8将使用“
filename
”参数 .那个RFC 5987反过来引用RFC 2231,它描述了实际的格式 . 2231主要用于邮件,5987告诉我们哪些部分也可用于HTTP标头 . 不要将此与
multipart/form-data
HTTP正文中使用的MIME标头混淆,后者由RFC 2388(特别是section 4.4)和HTML 5 draft控制 .Jim在Jim中提到的以下文件在他的答复中进一步解决了这个问题,这里绝对值得直接注意:
Test Cases for HTTP Content-Disposition header and RFC 2231/2047 Encoding
在asp.net mvc2我使用这样的东西:
我想如果你不使用mvc(2)你可以使用编码文件名
我使用以下代码片段进行编码(假设fileName包含文件的文件名和扩展名,即:test.txt):
PHP:
Java的:
在ASP.NET Web API中,我url编码文件名:
将文件名放在双引号中 . 解决了我的问题 . 像这样:
http://kb.mozillazine.org/Filenames_with_spaces_are_truncated_upon_download
我在所有主流浏览器中测试了以下代码,包括较旧的浏览器(通过兼容模式),它适用于所有地方:
如果你使用的是nodejs后端,你可以使用我发现的以下代码here
我最终在我的"download.php"脚本中使用了以下代码(基于this blogpost和these test cases) .
这使用filename = "..."的标准方式,只要使用iso-latin1和"safe"字符;如果没有,它会添加文件名* = UTF-8''url-encoded方式 . 根据this specific test case,它应该可以在MSIE9上运行,最近在FF,Chrome,Safari上运行;在较低的MSIE版本上,它应该提供包含文件名的ISO8859-1版本的文件名,并且在此编码中不包含字符的下划线 .
最后说明:最大值apache上每个头字段的大小为8190字节 . UTF-8每个字符最多可包含四个字节;在rawurlencode之后,每个字符x3 = 12个字节 . 相当低效,但理论上仍然可以在文件名中包含超过600个“微笑”%F0%9F%98%81 .
在PHP中,它为我做了(假设文件名是UTF8编码):
针对IE8-11,Firefox和Chrome进行了测试 .
如果浏览器可以解释filename * = utf-8,它将使用文件名的UTF8版本,否则它将使用解码的文件名 . 如果您的文件名包含无法在ISO-8859-1中表示的字符,您可能需要考虑使用
iconv
.经典ASP解决方案
大多数现代浏览器都支持将
Filename
现在作为UTF-8
传递,但是我使用的文件上传解决方案基于FreeASPUpload.Net(网站不再存在,链接指向archive.org),它不支持't work as the parsing of the binary relied on reading single byte ASCII encoded strings, which worked fine when you passed UTF-8 encoded data until you get to characters ASCII doesn' .但是我能够找到一个解决方案来获取代码来读取和解析二进制文件为UTF-8 .
通过在我自己的代码中实现
include_aspuploader.asp
的BytesToString()
函数,可以获得Pure ASP File Upload,我可以使UTF-8
文件名工作 .有用的链接
Multipart/form-data and UTF-8 in a ASP Classic application
Unicode, UTF, ASCII, ANSI format differences
我们在Web应用程序中遇到了类似的问题,最后通过阅读来自HTML
<input type="file">
的文件名,并在新的HTML<input type="hidden">
中以url编码的形式设置 . 当然,我们必须删除某些浏览器返回的"C:\fakepath"之类的路径 .当然,这并不直接回答OP问题,但可能是其他人的解决方案 .
我通常使用URL编码(使用%xx)文件名,它似乎适用于所有浏览器 . 无论如何,您可能想要进行一些测试 .
我找到了解决方案,适用于我的所有浏览器(即我安装的所有浏览器 - IE8,FF16,Opera 12,Chrome 22) .
我的解决方案在其他主题中描述:Java servlet download filename special characters
我的解决方案基于以下事实:浏览器如何尝试从
filename
参数读取值 . 如果filename
参数中没有指定字符集(例如filename*=utf-8''test.xml
),则浏览器希望该值以浏览器的本机编码进行编码 .不同的浏览器需要不同的本机编码 . 通常浏览器的本机编码是utf-8(FireFox,Opera,Chrome) . 但IE的原生编码是Win-1250 . (我对其他浏览器一无所知 . )
因此,如果我们将值放入
filename
parametr,即根据用户的浏览器由utf-8 / win-1250编码,它应该可以工作 . 至少,它对我有用 .简而言之,如果我们有一个名为
omáčka.xml
的文件,对于FireFox,Opera和Chrome我会响应此 Headers (以utf-8编码):
对于IE我响应这个 Headers (以win-1250编码):
Java示例是in my post,如上所述 .