Кириллица в параметре Filename заголовка Content-Disposition

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

Возникла следующая проблема. Имеется веб-приложение (клиент на 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 и имя файла получается с кракозябрами.

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

В общем, я в тупике. Был бы очень благодарен за совет, может быть есть гораздо более простой способ решения моей задачи, а я его в упор не вижу.
  • Вопрос задан
  • 40592 просмотра
Решения вопроса 1
@egorinsk
Нельзя использовать Content-Disposition для задания имени файла, так как он поддерживает только Ascii. Решение — используйте ссылки для скачивания вида:

/download/12345/Отчет о недвижимости.xls

И все у вас будет работать как надо.
Ответ написан
Пригласить эксперта
Ответы на вопрос 4
EugeneOZ
@EugeneOZ
Транслитерируйте кириллицу в латиницу, пробельные символы — в подчёркивания.
Ответ написан
Комментировать
lightsgoout
@lightsgoout
Ответ написан
Комментировать
@AndyGrom
Web-developer
Для того, чтобы IE нормально понимал имена файлов на русском, мне приходится делать следующий финт на стороне сервера.
var fileName = '.....';
var name = isIE(request.headers['user-agent'])? encodeURIComponent(fileName): fileName;
response.set({
     'Content-Type' : contentType,
     'Content-Disposition' : 'attachment; filename="' + name + '"'
});

Вероятно, что для Вас здесь главным будет использование encodeURIComponent
Ответ написан
Комментировать
@MisterParser
Проверено на Chrome 68.0.3440.84, Firefox 66.0.2, IE 11.648.17134.0
amigosteam.ru/blog/item/16-contentdisposition
Только нужно заменить msie из статьи по ссылке на trident.
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы