Особенности работы с русской кодировкой при загрузке файлов через aiohttp

Моя цель - предложение широкого ассортимента товаров и услуг на постоянно высоком качестве обслуживания по самым выгодным ценам.

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

Описание ошибки

Наткнулись на ошибку случайно: в одной из интеграций стояла «маска» на символы в имени файлов, и в какой-то момент сработало оповещение о количестве ошибок в отправленных запросах. Исходные файлы имели имена вида «тест.png», но после загрузки в систему превращались в «%D1%82%D0%B5%D1%81%D1%82.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://habr.com/ru/companies/domclick/articles/732620/


Интересные статьи

Интересные статьи

Продолжаем изучение внешнего RS485/ModbusRTU блока расширения MA01-AACX2240 компании EBYTE. Сегодня мы разберём устройство Modbus RTU регистров, принципов доступа к ним и получения информации от M...
Blazor Server - технология для простого написания Web-систем на платформе .Net. Для удобной работы с базами данных была создана библиотека Entity Framework, которая позволяет работать программисту нап...
Люди меняют профессию по разным причинам — надоело, босс не очень или платят мало. Да и мало ли ещё что. Важно, что у всех есть вероятность однажды оказаться перед пустой...
Мы в Wrike решили сделать встречу для сотрудников креативных команд – дизайнеров, маркетологов, проджект-менеджеров – чтобы поговорить об эффективных процессах там, где рутина мож...
С недавних пор я снова перешёл на 100% работу из дома и стал использовать стол для работы стоя. Хочу поделиться дампом своего опыта на тему здоровья, призвать закончить прокрастинировать и начать...