我知道这是一个旧帖子,但它仍然非常重要。我发现现代浏览器支持rfc5987,它允许utf-8编码,百分比编码(URL编码)。然后,朴素的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和更早版本也不支持它,您需要使用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中进行了测试,并使用以下文件名下载:你好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:除了android和IE7 + 8以外,按照RFC6266将两个文件名组合在一起的做法是可行的,我已经更新了代码以反映这一点。感谢您的建议。
@Thilo:不了解GoodReader或任何其他非浏览器。使用Android方法可能会有些运气。
@Alex Zhukovskiy:我不知道为什么,但是正如在Connect上讨论的那样,它似乎无法很好地工作。