Eu sei que este é um post antigo, mas ainda é muito relevante. Eu descobri que os navegadores modernos oferecem suporte ao rfc5987, que permite a codificação utf-8, porcentagem codificada (codificada por url). Então o arquivo Naïve.txt se torna:
Content-Disposition: attachment; filename*=UTF-8''Na%C3%AFve%20file.txt
O Safari (5) não suporta isso. Em vez disso, você deve usar o padrão Safari para escrever o nome do arquivo diretamente no cabeçalho codificado utf-8:
Content-Disposition: attachment; filename=Naïve file.txt
O IE8 e versões anteriores também não são compatíveis e você precisa usar o padrão IE de codificação utf-8, porcentagem codificada:
Content-Disposition: attachment; filename=Na%C3%AFve%20file.txt
No ASP.Net, uso o seguinte código:
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);
Testei o acima usando IE7, IE8, IE9, Chrome 13, Opera 11, FF5, Safari 5.
Atualização em novembro de 2013:
Aqui está o código que atualmente uso. Eu ainda tenho que dar suporte ao IE8, então não consigo me livrar da primeira parte. Acontece que os navegadores no Android usam o gerenciador de downloads interno do Android e não podem analisar nomes de arquivos de maneira confiável da maneira padrão.
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);
Os itens acima agora foram testados no IE7-11, Chrome 32, Opera 12, FF25, Safari 6, usando este nome de arquivo para download: 你好 abcABCæøåÆØÅäöüïëêîâéíáóúúññ½§! ^ ~ '-_,;. txt
No IE7, ele funciona para alguns caracteres, mas não para todos. Mas quem se importa com o IE7 hoje em dia?
Essa é a função que eu uso para gerar nomes de arquivos seguros para o Android. Observe que não sei quais caracteres são suportados no Android, mas testei que eles funcionam com certeza:
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: Eu testei no IE7 e IE8 e acabei não precisando escapar do apóstrofo ('). Você tem um exemplo em que falha?
@Dave Van den Eynde: Combinar os dois nomes de arquivos em uma linha, de acordo com o RFC6266, exceto o Android e o IE7 + 8, e atualizei o código para refletir isso. Obrigado pela sugestão.
@ Thilo: Não faço ideia do GoodReader ou de qualquer outro navegador que não seja. Você pode ter alguma sorte usando a abordagem do Android.
@Alex Zhukovskiy: Não sei por que, mas, como discutido no Connect , não parece funcionar muito bem.