Я знаю, что это старый пост, но он все еще очень актуален. Я обнаружил, что современные браузеры поддерживают rfc5987, который допускает кодирование utf-8 в процентах (в кодировке url). Тогда Наивный файл .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:
Вот код, который я сейчас использую. Мне все еще нужно поддерживать 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, это не очень хорошо работает.