Юникод в заголовке Content-Disposition
-
23-09-2019 - |
Вопрос
Я использую объект HttpContext, реализованный в дочернем элементе HttpHandler, для загрузки файла, когда у меня в имени файла есть символы, отличные от ascii, это выглядит странно в IE, тогда как в Firefox это выглядит нормально.
ниже приведен код:-
context.Response.ContentType = ".cs";
context.Response.AppendHeader("Content-Length", data.Length.ToString());
context.Response.AppendHeader("Content-Disposition", String.Format("attachment; filename={0}",filename));
context.Response.OutputStream.Write(data, 0, data.Length);
context.Response.Flush();
когда я поставляю 'ß' 'ä' 'ö' 'ü' 'Ã3' 'ß' 'ä' 'ö' 'ü' 'Ã3' в поле Имя файла это выглядит по-другому, чем то, что у меня в имени файла это выглядит нормально в Firefox.добавление EncodingType и charset оказалось бесполезным.
В ie это '¡å''ä''ö''ü''ó''ß''ä''ö''ƒ⠼'_'ƒÂ3' а в firefox это 'АЙ' 'Яй' 'Яй' 'Яй' 'Яй' 'Яй' 'Яй'Яй'Яй'Яй'Яй'Яй'Яй'Яй'Яй'Яй'Яй'Яй'Яй'Яй'Яй'Яй'Яй'Яй'Яй'Яй'Яй'Яй'Яй'Яй'Яй'Яй'.
Есть идеи, как это можно исправить?
Решение
У меня была похожая проблема.Вы должны использовать HttpUtility.UrlEncode (URL-код) или Сервер.UrlEncode чтобы закодировать имя файла.Также я помню, что firefox в этом не нуждался.Более того, это испортило имя файла, когда оно закодировано в URL.Мой код:
// IE needs url encoding, FF doesn't support it, Google Chrome doesn't care
if (Request.Browser.IsBrowser ("IE"))
{
fileName = Server.UrlEncode(fileName);
}
Response.Clear ();
Response.AddHeader ("content-disposition", String.Format ("attachment;filename=\"{0}\"", fileName));
Response.AddHeader ("Content-Length", data.Length.ToString (CultureInfo.InvariantCulture));
Response.ContentType = mimeType;
Response.BinaryWrite(data);
Редактировать
Я более внимательно прочитал спецификацию.Прежде всего RFC2183 заявляет , что:
Текущая грамматика [RFC 2045] ограничивает значения параметров (и, следовательно, имена файлов с размещением содержимого) US-ASCII.
Но затем я нашел ссылки на то, что [RFC 2045] является абсолютным, и нужно ссылаться RFC 2231, в котором говорится:
Звездочки ("*") используются повторно для обеспечения индикатора того, что язык и информация о наборе символов присутствуют и используется кодировка.Одна кавычка ("'") используется для разграничения набора символов и информации о языке в начале параметра значение.Знаки процента ("%") используются в качестве флага кодирования, который согласуется с RFC 2047.
Это означает, что вы можете использовать UrlEncode для символов, отличных от ascii, при условии, что вы включаете кодировку, указанную в rfc.Вот один из примеров:
string.Format("attachment; filename=\"{0}\"; filename*=UTF-8''{0}", Server.UrlEncode(fileName, Encoding.UTF8));
Обратите внимание , что filename
входит в дополнение к filename*
для обратной совместимости.Вы также можете выбрать другую кодировку и соответствующим образом изменить параметр, но UTF-8 охватывает все.
Другие советы
HttpUtility.UrlPathEncode может быть лучшим вариантом.Поскольку URLEncode заменит пробелы знаками '+'.
Для меня это решение работает во всех основных браузерах:
Response.AppendHeader("Content-Disposition", string.Format("attachment; filename*=UTF-8''{0}", HttpUtility.UrlPathEncode(fileName).Replace(",", "%2C"));
var mime = MimeMapping.GetMimeMapping(fileName);
return File(fileName, mime);
Используя ASP.NET MVC 3.
Замена необходима, потому что Chrome не любит запятую (,) в значениях параметров: http://www.gangarasa.com/lets-Do-GoodCode/tag/err_response_headers_multiple_content_disposition/
Возможно, вы захотите прочитать RFC 6266 и посмотрите на тесты по адресу http://greenbytes.de/tech/tc2231/.
Для меня это решило проблему:
var result = new HttpResponseMessage(HttpStatusCode.OK)
{
Content = new ByteArrayContent(data)
};
result.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment")
{
FileNameStar = "foo-ä-€.html"
};
Когда я просматриваю repsonse в fiddler, я вижу, что имя файла автоматически было закодировано с использованием UTF-8:
Пример ответа скрипача с закодированным именем файла размещения содержимого с использованием UTF-8
Если мы посмотрим на значение заголовка Content-Disposition, мы увидим, что оно будет таким же, как у @Johannes Geyer в его ответе.Единственное отличие заключается в том, что нам не нужно было выполнять кодирование самостоятельно, об этом позаботится класс ContentDispositionHeaderValue.
Я использовал тестовые наборы для заголовка Content-Disposition на: http://greenbytes.de/tech/tc2231/ как упоминал Джулиан Решке.Информацию о классе ContentDispositionHeaderValue можно найти в MSDN.
Для Asp.Net Core (версия 2 на момент этого поста) UrlPathEncode устарел, вот как достичь желаемого результата:
System.Net.Mime.ContentDisposition cd = new System.Net.Mime.ContentDisposition
{
FileName = Uri.EscapeUriString(fileName),
Inline = true // false = prompt the user for downloading; true = browser to try to show the file inline
};
Response.Headers.Add("Content-Disposition", cd.ToString());
Я использую Uri.EscapeUriString
for преобразует все символы в их шестнадцатеричное представление, и string.Normalize
для нормализации Юникода форма C.(протестировано в ASP.NET MVC5 framework 4.5)
var contentDispositionHeader = new System.Net.Mime.ContentDisposition
{
Inline = false,
FileName = Uri.EscapeUriString(Path.GetFileName(pathFile)).Normalize()
};
Response.Headers.Add("Content-Disposition", contentDispositionHeader.ToString());
string mimeType = MimeMapping.GetMimeMapping(Server.MapPath(pathFile));
return File(file, mimeType);