如何编码内容的文件名参数
希望强制下载资源而不是直接在Web浏览器中呈现资源的Web应用程序在表单的HTTP响应中发出Content-Disposition
标头:
Content-Disposition: attachment; filename=FILENAME
filename
参数可用于为浏览器下载资源的文件建议名称。 但RFC 2183(Content-Disposition)在第2.3节(文件名参数)中声明文件名只能使用US-ASCII字符:
目前[RFC 2045]语法将参数值(以及Content-Disposition文件名)限制为US-ASCII。 我们认识到允许在文件名中使用任意字符集的强烈愿望,但是定义必要的机制超出了本文档的范围。
尽管如此,仍有经验证据表明,目前大多数流行的Web浏览器似乎仍允许非US-ASCII字符(对于缺乏标准)对文件名的编码方案和字符集规范持不同意见。 问题是,如果需要将文件名“naïvefile”(不带引号且第三个字母是U + 00EF)编码到Content-Disposition标头中,那么常用浏览器使用的各种方案和编码是什么?
为了这个问题的目的,流行的浏览器是:
在提议的RFC 5987“用于超文本传输协议(HTTP)头字段参数的字符集和语言编码”中讨论了这一点,包括对浏览器测试和向后兼容性的链接。
RFC 2183指出,这样的头文件应该根据RFC 2184进行编码,而RFC 2184已经被RFC 2231废弃,该文件已经被上面的RFC草案所涵盖。
我知道这是一个旧帖子,但它仍然非常相关。 我发现现代浏览器支持rfc5987,它允许utf-8编码,百分比编码(url编码)。 然后Naïvefile.txt变成:
Content-Disposition: attachment; filename*=UTF-8''Na%C3%AFve%20file.txt
Safari(5)不支持这一点。 相反,您应该使用Safari标准直接在UTF-8编码头中编写文件名:
Content-Disposition: attachment; filename=Naïve file.txt
IE8和更旧版本不支持它,你需要使用utf-8编码的IE标准,百分比编码:
Content-Disposition: attachment; filename=Na%C3%AFve%20file.txt
在ASP.Net中我使用下面的代码:
string contentDisposition;
if (Request.Browser.Browser == "IE" && (Request.Browser.Version == "7.0" || Request.Browser.Version == "8.0"))
contentDisposition = "attachment; filename=" + Uri.EscapeDataString(fileName);
else if (Request.Browser.Browser == "Safari")
contentDisposition = "attachment; filename=" + fileName;
else
contentDisposition = "attachment; filename*=UTF-8''" + Uri.EscapeDataString(fileName);
Response.AddHeader("Content-Disposition", contentDisposition);
我使用IE7,IE8,IE9,Chrome 13,Opera 11,FF5,Safari 5测试了上述内容。
2013年11月更新 :
这是我目前使用的代码。 我仍然需要支持IE8,所以我无法摆脱第一部分。 事实证明,Android上的浏览器使用内置的Android下载管理器,它不能可靠地以标准方式解析文件名。
string contentDisposition;
if (Request.Browser.Browser == "IE" && (Request.Browser.Version == "7.0" || Request.Browser.Version == "8.0"))
contentDisposition = "attachment; filename=" + Uri.EscapeDataString(fileName);
else if (Request.UserAgent != null && Request.UserAgent.ToLowerInvariant().Contains("android")) // android built-in download manager (all browsers on android)
contentDisposition = "attachment; filename="" + MakeAndroidSafeFileName(fileName) + """;
else
contentDisposition = "attachment; filename="" + fileName + ""; filename*=UTF-8''" + Uri.EscapeDataString(fileName);
Response.AddHeader("Content-Disposition", contentDisposition);
以上现在已经在IE7-11,Chrome 32,Opera 12,FF25,Safari 6中测试过,使用这个文件名进行下载:你好! ^〜'-_,;。TXT
在IE7上它适用于某些字符,但不是全部。 但是现在谁在乎IE7呢?
这是我用来为Android生成安全文件名的功能。 请注意,我不知道哪些字符在Android上受支持,但是我已经测试了这些功能的确如此:
private static readonly Dictionary<char, char> AndroidAllowedChars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ._-+,@£$€!½§~'=()[]{}0123456789".ToDictionary(c => c);
private string MakeAndroidSafeFileName(string fileName)
{
char[] newFileName = fileName.ToCharArray();
for (int i = 0; i < newFileName.Length; i++)
{
if (!AndroidAllowedChars.ContainsKey(newFileName[i]))
newFileName[i] = '_';
}
return new string(newFileName);
}
@TomZ:我测试了IE7和IE8,结果证明我不需要撇开撇号(')。 你有一个失败的例子吗?
@Dave Van den Eynde:根据RFC6266在一行上结合两个文件名,除Android和IE7 + 8之外,我更新了代码以反映这一点。 感谢您的建议。
@Thilo:对GoodReader或任何其他非浏览器不了解。 使用Android方法可能会带来一些好运。
@亚历克斯·朱可夫斯基:我不知道为什么,但正如Connect上所讨论的那样,它看起来不太好。
在Content-Disposition
没有可互操作的方式来编码非ASCII名称。 浏览器兼容性一团糟。
在Content-Disposition
使用UTF-8的理论上正确的语法非常奇怪: filename*=UTF-8''foo%c3%a4
(是的,这是一个星号,除了中间的空单引号外没有引号)
这个头文件不太标准(HTTP / 1.1规范承认它的存在,但不要求客户端支持它)。
有一个简单且非常强大的替代方法: 使用包含所需文件名的URL 。
当最后一个斜杠后面的名称是您想要的名称时,您不需要任何额外的标头!
这个技巧的作品:
/real_script.php/fake_filename.doc
如果您的服务器支持URL重写(例如Apache中的mod_rewrite
),那么您可以完全隐藏脚本部分。
URL中的字符应该是UTF-8,逐字节为urlencode:
/mot%C3%B6rhead # motörhead
链接地址: http://www.djcxy.com/p/3771.html
上一篇: How to encode the filename parameter of Content
下一篇: Binary Data in JSON String. Something better than Base64