Content disposition attachment filename кириллица

Заголовок Content-Disposition вместе с директивой attachment помогают заставить браузер скачивать файл по ссылке, вместо его отображения. Параметр filename позволяет задать для приложенного файла свое имя. В документе RFC 2183, который описывает использование этого заголовка, ссылающемся в свою очередь на RFC 2045, для значений параметров разрешено использовать только US-ASCII символы. Это означает, что мы не можем задать имя файла, как параметр, например, с использование символов кириллицы. Практика показывает, что современные браузеры умеют корректно обрабатывать этот параметр и с символами, находящимися за пределами US-ASCII таблицы.

Для корректной обработки браузерами значений параметра filename можно использовать такую функцию:

Добрый день, уважаемы хабра-юзеры.

Возникла следующая проблема. Имеется веб-приложение (клиент на js, сервер на php) и некое файловое хранилище. Чтобы скачать файл из хранилища, клиентская часть веб-приложения шлет запрос на серверную, там выполняется бизнес логика (проверка прав доступа и т.д.), если все ок, то отдается ссылка на файл. Затем клиентская часть делает редирект на эту ссылку. На сервере файлового хранилища стоит nginx, который и отдает файлы. Имена у файлов представляют собой набор символов без смыслового содержания (просто GUID), что не очень нравилось пользователям. Они хотели бы, чтобы при скачивании у файла было такое же имя, как у соответствующей ему сущности в веб-приложении. Поскольку переименовывать файлы очень не хотелось бы по некоторым причинам, было придумано следующее:

1. При формировании ссылки в серверной части веб-приложения к ней цепляется GET-параметр, в котором содержится приемлемое для пользователя имя файла.
2. В конфиге nginx при отдаче файла этот параметр подставляется в заголовок Content-Disposition.
(add_header Content-Disposition ‘attachment;Filename=$args’;)

Проблемы начались с подстановкой в Content-Disposition русского текста.
Во-первых, firefox при редиректе на хранилище делает urlencode ссылки. И nginx в Content-Disposition подставляет закодированную строку. Соответственно firefox предлагает сохранить файл также под закодированным именем.
Во-вторых, даже если в Content-Disposition будет незакодированная строка, но в UTF-8 с кириллицей, то IE ничего знать не хочет о том, что это UTF-8. Интерпретирует его как cp1251 и имя файла получается с кракозябрами.

Читайте также:  Anker 30w usb c

В общем, данная схема нормально работает только в хроме. Если я не ошибаюсь, то с проблемой номер 1 (urlencode) можно справиться, если пересобрать nginx из исходников, включив в него модуль ngx_set_misc. Тогда в конфиге nginx можно будет с помощью set_unescape_uri сделать urldecode для имени файла перед тем как вставлять его в заголовок Content-Disposition. Но к такому варианту хотелось бы прибегать в последнюю очередь.
А как решить проблему с IE — вообще не знаю.

В общем, я в тупике. Был бы очень благодарен за совет, может быть есть гораздо более простой способ решения моей задачи, а я его в упор не вижу.

Web applications that want to force a resource to be downloaded rather than directly rendered in a Web browser issue a Content-Disposition header in the HTTP response of the form:

Content-Disposition: attachment; filename=FILENAME

The filename parameter can be used to suggest a name for the file into which the resource is downloaded by the browser. RFC 2183 (Content-Disposition), however, states in section 2.3 (The Filename Parameter) that the file name can only use US-ASCII characters:

Current [RFC 2045] grammar restricts parameter values (and hence Content-Disposition filenames) to US-ASCII. We recognize the great desirability of allowing arbitrary character sets in filenames, but it is beyond the scope of this document to define the necessary mechanisms.

There is empirical evidence, nevertheless, that most popular Web browsers today seem to permit non-US-ASCII characters yet (for the lack of a standard) disagree on the encoding scheme and character set specification of the file name. Question is then, what are the various schemes and encodings employed by the popular browsers if the file name “naïvefile” (without quotes and where the third letter is U+00EF) needed to be encoded into the Content-Disposition header?

Читайте также:  Как обрезать фото в виде круга

For the purpose of this question, popular browsers being:

  • Firefox
  • Internet Explorer
  • Safari
  • Google Chrome
  • Opera

18 Answers 18

There is discussion of this, including links to browser testing and backwards compatibility, in the proposed RFC 5987, "Character Set and Language Encoding for Hypertext Transfer Protocol (HTTP) Header Field Parameters."

RFC 2183 indicates that such headers should be encoded according to RFC 2184, which was obsoleted by RFC 2231, covered by the draft RFC above.

I know this is an old post but it is still very relevant. I have found that modern browsers support rfc5987, which allows utf-8 encoding, percentage encoded (url-encoded). Then Naïve file.txt becomes:

Safari (5) does not support this. Instead you should use the Safari standard of writing the file name directly in your utf-8 encoded header:

IE8 and older don’t support it either and you need to use the IE standard of utf-8 encoding, percentage encoded:

In ASP.Net I use the following code:

I tested the above using IE7, IE8, IE9, Chrome 13, Opera 11, FF5, Safari 5.

Update November 2013:

Here is the code I currently use. I still have to support IE8, so I cannot get rid of the first part. It turns out that browsers on Android use the built in Android download manager and it cannot reliably parse file names in the standard way.

The above now tested in IE7-11, Chrome 32, Opera 12, FF25, Safari 6, using this filename for download: 你好abcABCæøåÆØÅäöüïëêîâéíáóúýñ½§!#¤%&()=`@£$€<[]>+´¨^

On IE7 it works for some characters but not all. But who cares about IE7 nowadays?

Читайте также:  Как вытащить таблетку биос

This is the function I use to generate safe file names for Android. Note that I don’t know which characters are supported on Android but that I have tested that these work for sure:

@TomZ: I tested in IE7 and IE8 and it turned out that I did not need to escape apostrophe (‘). Do you have an example where it fails?

@Dave Van den Eynde: Combining the two file names on one line as according to RFC6266 works except for Android and IE7+8 and I have updated the code to reflect this. Thank you for the suggestion.

@Thilo: No idea about GoodReader or any other non-browser. You might have some luck using the Android approach.

@Alex Zhukovskiy: I don’t know why but as discussed on Connect it doesn’t seem to work terribly well.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Adblock detector