我知道这是一个旧帖子,但它仍然非常相关。我发现现代浏览器支持 rfc5987,它允许 utf-8 编码、百分比编码(url 编码)。然后 Naïve file.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 及更早版本也不支持,需要使用 IE 标准的 utf-8 编码,百分比编码:
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 中测试,使用此文件名进行下载:你好abcABCæøåÆØÅäöüïëêîâéíáóúýñ½§!#¤%&()=`@£$€{[]}+´¨ ^~'-_,;.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 方法可能会有一些运气。
@Alex Zhukovskiy:我不知道为什么,但正如Connect上所讨论的,它似乎不太好用。