Потеря кириллицы в имени файла при отправке через Expo и Multer

    Почему теряется кириллица в поле originalname?

    При отправке файлов с кириллическими именами из приложения Expo на бэкенд на Node.js с Multer часто возникает проблема: поле originalname содержит только расширение (например, '.jpg') вместо полного имени ('Аватар.jpg'). Это связано с тем, что Multer по умолчанию использует кодировку Latin-1 (ISO-8859-1) для заголовка Content-Disposition, где передаётся имя файла. Кириллические символы в этой кодировке не поддерживаются и заменяются на пустые или некорректные значения.

    Как Multer обрабатывает имена файлов?

    Multer получает имя файла из заголовка Content-Disposition в multipart-запросе. Если имя содержит символы вне диапазона Latin-1 (например, кириллицу), они теряются. Стандарт требует кодировать такие имена через RFC 5987 или использовать URL-кодирование, но не все клиенты и библиотеки это поддерживают. В вашем случае Expo отправляет имя в сыром виде, и Multer не может его правильно декодировать.

    Почему это происходит именно с Expo?

    Expo использует FormData API, который при добавлении файла через объект с полями uri, type, name передаёт имя файла в заголовке Content-Disposition без дополнительной обработки. Если имя содержит не-ASCII символы, они не кодируются автоматически. В результате на сервере Multer видит пустую строку перед расширением.

    Как решить проблему с кодировкой имени файла?

    Есть несколько способов решить проблему:

    • Кодировать имя на клиенте: Перед отправкой замените кириллицу на латиницу или используйте URL-кодирование (encodeURIComponent) для имени файла. На сервере декодируйте его обратно.
    • Передать имя отдельным полем: Добавьте в FormData дополнительное поле с оригинальным именем файла (например, 'fileName'), а сам файл называйте транслитом или хешем. На сервере используйте это поле для сохранения.
    • Настроить Multer: Используйте опцию filename в Multer, чтобы переопределить имя файла на основе исходного, но это не решит проблему получения оригинального имени из заголовка.

    Пример кода для клиента (Expo)

    Вот как можно модифицировать отправку файла, чтобы сохранить кириллическое имя:

    const formData = new FormData();
    formData.append('taskData', JSON.stringify(taskData));
    if (files) {
      files.forEach((file) => {
        // Кодируем имя файла в base64 или URL-encode
        const encodedName = btoa(unescape(encodeURIComponent(file.filePickerName)));
        formData.append('files', {
          uri: file.filePickerUri,
          type: file.filePickerType,
          name: encodedName,
        } as any);
        // Отправляем оригинальное имя отдельно
        formData.append('originalFileNames', file.filePickerName);
      });
    }

    Пример кода для сервера (NestJS с Multer)

    На сервере декодируйте имя файла из отдельного поля:

    @Put()
    @UseInterceptors(FilesInterceptor('files'))
    async updateTask(@Body() body: any, @UploadedFiles() files: Express.Multer.File[]) {
      const originalNames = body.originalFileNames;
      if (Array.isArray(originalNames)) {
        files.forEach((file, index) => {
          // Декодируем имя из base64
          const decodedName = decodeURIComponent(escape(atob(file.originalname)));
          console.log('Decoded name:', decodedName);
          // Используем decodedName для сохранения
        });
      }
    }

    Другие возможные причины потери кириллицы

    Помимо проблемы с кодировкой в Multer, проверьте следующее:

    • ValidationPipe: Если вы используете ValidationPipe с опцией transform, он может изменять тело запроса. Убедитесь, что он не затрагивает файлы.
    • Прокси или балансировщик: Nginx или другие прокси могут перекодировать заголовки. Проверьте конфигурацию.
    • Кодировка запроса: Убедитесь, что заголовок Content-Type включает правильную кодировку (обычно multipart/form-data без указания charset).

    Итоги

    Потеря кириллицы в имени файла - распространённая проблема при работе с multipart-запросами. Лучшее решение - передавать оригинальное имя отдельным полем в FormData, а имя файла в запросе кодировать (например, через base64). Это гарантирует сохранность кириллицы и совместимость с Multer.

    Часто задаваемые вопросы