В ходе исследования непонятного бага с битой кодировкой в именах загружаемых файлов мы столкнулись с непредвиденным поведением популярной библиотеки aiohttp. Решая эту проблему, мы получили полезный опыт, которым хочу с вами поделиться.
Описание ошибки
![](https://habrastorage.org/getpro/habr/upload_files/484/83c/93a/48483c93a4b0400ae723b44ba42ca710.png)
Наткнулись на ошибку случайно: в одной из интеграций стояла «маска» на символы в имени файлов, и в какой-то момент сработало оповещение о количестве ошибок в отправленных запросах. Исходные файлы имели имена вида «тест.png», но после загрузки в систему превращались в «%D1%82%D0%B5%D1%81%D1%82.png».
Исправление ошибки
![](https://habrastorage.org/getpro/habr/upload_files/3c9/b97/b25/3c9b97b255cdc7ff9aa2327014f84c27.png)
Для решения проблемы пришлось последовательно проверить каждую точку взаимодействия с этим файлом в системе, и в итоге нашли место с превращением файла «тест.pdf» в «%D1%82%D0...».
Для загрузке на Filestorage мы использовали представленный в базовой документации aiohttp способ загрузки (файлы небольшого размера):
url = 'http://httpbin.org/post'
files = {'file': open('тест.png', 'rb')}
await session.post(url, data=files)
Переход на способ загрузки с FormData()
не решал проблему:
url = 'http://httpbin.org/post'
data = FormData()
data.add_field('file',
open('тест.png', 'rb'),
filename='тест.png',
content_type='image/png')
await session.post(url, data=data)
Быстро разобраться в таком поведении библиотеки aiohttp не получилось, поэтому пришлось глубже изучить документацию, провалиться в реализацию post-метода самой библиотеки и изучить похожие вопросы на просторах интернета. Как ни странно, на такую проблему наткнулись коллеги при использовании китайских символов, и способ решения был рабочий:
url = 'http://httpbin.org/post'
# По умолчанию quote_fields=True, что приводит к замещению русских букв на %xx
data = FormData(quote_fields=False)
data.add_field('file',
open('тест.png', 'rb'),
filename='тест.png',
content_type='image/png')
await session.post(url, data=data)
Осталось понять почему библиотека так себя ведёт. Оказалось, всё дело в стандарте RFC 7578: по умолчанию выполняется квотирование значений для 7-битных MIME-заголовков. Если окружающие сервисы поддерживают имена файлов с расширенными ASCII-символами (больше 7 бит), то смело указываем quote_fields=False
, и тогда проблема с нелатинскими буквами уйдёт.
Заключение
![](https://habrastorage.org/getpro/habr/upload_files/0ce/2ef/ad3/0ce2efad3fa4ed4f1ad5dae87cad783d.png)
Даже стандартный для рынка инструмент может принести сюрпризы, и не каждую ошибку можно решить без глубокого погружения в код. Надеюсь, наш опыт будет полезен русскоязычному сообществу.