Гид по технологиям

Загрузка изображений на сервер с помощью Multer в Node.js

7 min read Node.js Обновлено 19 Dec 2025
Загрузка изображений в Node.js с Multer
Загрузка изображений в Node.js с Multer

Буквенные кубики, составляющие слово «JAVASCRIPT»

Есть три основных способа хранить загружаемые файлы в приложениях на Node.js: сохранить изображения на самом сервере (файловая система), сохранить двоичные данные или base64 в базе данных, либо использовать облачное хранилище (например, AWS S3). В этой статье фокус — на первом варианте: сохранение изображений прямо на сервере с помощью Multer — лёгкого и популярного middleware для Express.

Почему этот подход

  • Простота: файлы доступны сразу на диске, легко отлаживать локально.
  • Низкий порог входа: не требуется облачный аккаунт или схема хранения в БД.
  • Контроль: вы управляете правами доступа и структурой каталогов.

Когда не подходит: если нужно масштабируемое хранение файлов, распределённый доступ из разных инстансов или длительное хранение с геораспределённой репликацией — лучше использовать S3 или аналог.

Что вы получите из руководства

  • Пошаговая настройка проекта и Multer
  • Валидация расширений, MIME и размера файла (локализация единиц — 1 МБ)
  • Примеры маршрутов Express для одиночных и множественных загрузок
  • Пример HTML-формы и curl-запроса для тестирования
  • Чек-листы, критерии приёмки и тест-кейсы
  • Совет по безопасности, конфиденциальности и миграции на S3

Шаг 1: Подготовка окружения разработки

Проект находится в открытом репозитории под MIT, вы можете адаптировать код.

Создайте папку проекта и перейдите в неё:

mkdir multer-tutorial
cd multer-tutorial

Инициализируйте npm:

npm init -y

Установите зависимости:

npm install express multer

Создайте файл app.js в корне проекта и добавьте базовый Express-сервер:

// app.js
const express = require('express');
const app = express();

const port = process.env.PORT || 3000;

app.listen(port, () => {
  console.log(`App is listening on port ${port}`);
});

Примечание: локализация порта и путей остаётся стандартной. Для Windows используйте ту же команду mkdir, она работает в PowerShell/Command Prompt.

Шаг 2: Настройка Multer и Storage Engine

Импортируйте multer и создайте storage engine, который сохранит файлы в папке images вашего проекта.

const multer = require('multer');
const path = require('path');
const fs = require('fs');

// Убедиться, что папка ./images существует
const imagesDir = path.join(__dirname, 'images');
if (!fs.existsSync(imagesDir)) {
  fs.mkdirSync(imagesDir);
}

// Настройка storage engine
const storageEngine = multer.diskStorage({
  destination: './images',
  filename: (req, file, cb) => {
    cb(null, `${Date.now()}--${file.originalname}`);
  },
});

// Инициализация multer
const upload = multer({
  storage: storageEngine,
});

Пояснения:

  • destination: “./images” — относительный путь от корня проекта. На проде лучше использовать абсолютный путь или config.
  • filename: префикс Date.now() минимизирует коллизии имён. Можно добавить UUID для полностью гарантированных имён.

Важно: если приложение запускается в контейнере или read-only FS, сохранение на локальном диске не подойдёт.

Шаг 3: Валидация изображений (размер, расширение, MIME)

Добавим лимит размера и проверку типа файла. Локализуем размер в МБ: 1 000 000 байт ≈ 1 МБ.

const checkFileType = function (file, cb) {
  // Разрешённые расширения
  const fileTypes = /jpeg|jpg|png|gif|svg/;

  // Проверка расширения
  const extName = fileTypes.test(path.extname(file.originalname).toLowerCase());

  // Проверка MIME
  const mimeType = fileTypes.test(file.mimetype);

  if (mimeType && extName) {
    return cb(null, true);
  } else {
    cb(new Error('Error: You can Only Upload Images!!'));
  }
};

const uploadWithValidation = multer({
  storage: storageEngine,
  limits: { fileSize: 1_000_000 }, // 1 МБ
  fileFilter: (req, file, cb) => {
    checkFileType(file, cb);
  },
});

Замечания:

  • limits.fileSize — задаётся в байтах; здесь 1_000_000 ≈ 1 МБ. Подберите значение по потребностям.
  • Проверка расширения + MIME повышает надёжность. Для критичных приложений добавьте глубинную проверку типа файла (например, чтение заголовка файла).

Шаг 4: Использование Multer как middleware в маршрутах Express

Multer предоставляет удобные методы: single(field), array(field, maxCount), fields([…]) и .none().

Пример роутов для одиночной и множественной загрузки:

// Одиночная загрузка
app.post('/single', uploadWithValidation.single('image'), (req, res) => {
  if (req.file) {
    res.send('Single file uploaded successfully');
  } else {
    res.status(400).send('Please upload a valid image');
  }
});

// Множественная загрузка
app.post('/multiple', uploadWithValidation.array('images', 5), (req, res) => {
  if (req.files && req.files.length) {
    res.send('Multiple files uploaded successfully');
  } else {
    res.status(400).send('Please upload valid images');
  }
});

Где “image” и “images” — имена полей формы, которые ожидает сервер.

Примеры фронтенда и тестирования

HTML-форма для одиночной загрузки:



Форма для множественной загрузки (до 5 файлов):

Пример curl запроса для одиночного файла:

curl -F "image=@/path/to/file.jpg" http://localhost:3000/single

Для нескольких файлов:

curl -F "images=@/path/to/file1.jpg" -F "images=@/path/to/file2.png" http://localhost:3000/multiple

Обработка ошибок и middleware для ошибок Multer

Multer может генерировать ошибки (например, fileSize limit). Хорошая практика — иметь централизованный обработчик ошибок Express:

// Обработчик ошибок для multer и других ошибок
app.use((err, req, res, next) => {
  if (err instanceof multer.MulterError) {
    // Ошибки multer (например, превышен лимит)
    return res.status(400).send({ error: err.message });
  } else if (err) {
    return res.status(400).send({ error: err.message || 'Unknown error' });
  }
  next();
});

Совет: логируйте ошибки и детали запроса для отладки, но не выводите чувствительные данные пользователю.

Рекомендации по безопасности и конфиденциальности

  • Ограничьте размер файлов и допустимые типы.
  • Не используйте ненадёжные имена файлов без очистки: удаляйте опасные символы и ограничьте длину. В примере используется timestamp + оригинальное имя — рекомендуется дополнительно нормализовать имя.
  • Применяйте права доступа к директории: на проде файлы не должны сохраняться в публичной папке без контролируемого сервинга.
  • Проверяйте содержимое файла дополнительно (антивирус, проверка сигнатур), если есть риск вредоносных файлов.
  • Для данных пользователей, подпадающих под GDPR, сообщите в политике приватности, где хранятся файлы, как долго и как можно потребовать их удаления.

Альтернативы и миграция на облако

Когда хранение на локальном диске не подходит (масштабирование, отказоустойчивость), рассмотрите:

  • AWS S3 (рекомендуется для распределённых приложений). Multer имеет плагины/хранилища для S3.
  • Google Cloud Storage или Azure Blob Storage.
  • Хранение в базе данных (не для больших файлов; увеличивает нагрузку на БД).

Миграция: при переходе на S3 реализуйте middleware, который при загрузке сохраняет файл в S3, а в базе данных хранит ссылку и метаданные.

Критерии приёмки

  • Файлы с допустимыми расширениями и MIME успешно загружаются и сохраняются в ./images.
  • Файлы больше 1 МБ отклоняются с корректным сообщением.
  • Неподдерживаемые типы отклоняются с сообщением об ошибке.
  • После загрузки приложение возвращает 200 и подтверждение, либо 4xx с объяснением.
  • Все ошибки логируются на сервере без утечки личных данных.

Тест-кейсы и сценарии приёмо-сдаточных испытаний

  1. Тест: одиночная загрузка JPG размера 500 КБ — ожидаемый результат: 200 OK, файл в ./images.
  2. Тест: одиночная загрузка PNG размер 2 МБ — ожидаемый результат: 400 с сообщением о превышении размера.
  3. Тест: загрузка файла с расширением .exe, переименованного в .jpg — ожидаемый результат: отклонение (MIME или дальнейшая проверка сигнатур).
  4. Тест: множественная загрузка 3 изображений — ожидаемый результат: 200, все три файла сохранены.
  5. Тест: одновременные параллельные загрузки (нагрузочный тест) — поведение зависит от ресурсов; приложение не должно падать.

Чек-листы по ролям

Разработчик:

  • Добавить инициализацию images каталога при старте
  • Настроить проверку MIME и расширений
  • Покрыть роуты тестами

DevOps / SRE:

  • Убедиться, что диск имеет достаточный объём и политика ротации файлов
  • Настроить бэкапы или перенос на облако
  • Настроить мониторинг доступности и ошибок

Инженер по безопасности:

  • Проверить обработку пользовательских имён файлов
  • Настроить антивирусную проверку при необходимости
  • Проверить права доступа к каталогу

Мини-методология внедрения (пошаговая)

  1. Настройка локального хранилища и Multer (микроприложение на dev).
  2. Покрытие unit/integration тестами (curl/сценарии).
  3. Настройка логирования и обработки ошибок.
  4. Нагрузочное тестирование и оценка потребности в S3.
  5. Приёмка и документирование политики хранения/удаления.

Частые ошибки и пути их решения

  • Ошибка: ENOENT при сохранении файла — проверьте, создан ли каталог images и права доступа.
  • Ошибка: MulterError: File too large — увеличить limits.fileSize или сообщить пользователю лимит.
  • Ошибка: middleware не вызывается — убедитесь, что поле формы name совпадает с upload.single/array.

Пример улучшенной конфигурации с очисткой имён и UUID

const { v4: uuidv4 } = require('uuid');

const storageEngineSafe = multer.diskStorage({
  destination: './images',
  filename: (req, file, cb) => {
    const safeName = file.originalname.replace(/[^a-zA-Z0-9.\-_]/g, '_');
    cb(null, `${Date.now()}--${uuidv4()}--${safeName}`);
  },
});

Решение: когда сразу S3 выгоднее

  • Если у вас несколько реплик приложения, доступ к файлам нужен из разных инстансов.
  • Если ожидается большой объём хранения и долгосрочное хранение.
  • Если требуется CDN/глобальная доставка и контроль версий.

В таких случаях используйте multer-s3 или напрямую загружайте файл в S3 с фронтенда через пред-подписанные URL.

Пример: получение pre-signed URL для S3 (схема)

  • Сервер генерирует краткоживущий pre-signed URL и возвращает его клиенту.
  • Клиент загружает файл напрямую в S3, минуя сервер (уменьшает нагрузку на сервер).

Decision flow (упрощённый) — как выбрать хранилище

flowchart TD
  A[Нужно хранить файлы?] --> B{Несколько инстансов или масштаб?
}
  B -- Да --> C[S3 или облако]
  B -- Нет --> D[Локальный диск]
  D --> E{Нужен быстрый доступ и простота?}
  E -- Да --> F[Multer на локальном диске]
  E -- Нет --> C

Пример миграции: локальные файлы → S3 (идеи)

  • Написать скрипт, который читает ./images, загружает в S3 и обновляет метаданные (URL) в вашей БД.
  • После проверки целостности — переключить приложение на чтение с S3 и удалить локальные файлы.

Privacy / GDPR заметки

  • Убедитесь, что у вас есть правовая основа для хранения загруженного контента.
  • Предоставьте пользователям возможность удалить их данные (и связанные файлы).
  • Ведите журнал доступа к файлам при необходимости.

Краткое резюме

Multer — удобное и производительное решение для приёма файлов в Express-приложениях. Он прост в настройке для локального хранения и поддерживает дополнительные возможности: валидацию, лимиты и middleware для обработки ошибок. Если система масштабируется — стоит перейти на S3 или аналог.

Важно: всегда контролируйте типы файлов, размер, права доступа и обработку ошибок. При соблюдении этих правил загрузки будут надёжными и безопасными.


Ключевые ресурсы и примеры:

  • Multer официальная документация (npm)
  • Примеры использования multer-s3 для загрузки прямо в S3

Если нужно, могу:

  • Подготовить готовый репозиторий с конфигурацией (Express + Multer + tests).
  • Показать пример интеграции с AWS S3 (server-side upload и pre-signed URLs).
Поделиться: X/Twitter Facebook LinkedIn Telegram
Автор
Редакция

Похожие материалы

Удалить и открепить My AI в Snapchat
Социальные сети

Удалить и открепить My AI в Snapchat

Apple: чего ждать на презентации 14 сентября
Новости

Apple: чего ждать на презентации 14 сентября

Перезагрузка и сброс Chromecast и Google TV
Гайды

Перезагрузка и сброс Chromecast и Google TV

Как скрыть уведомления на блокировочном экране Android
Конфиденциальность

Как скрыть уведомления на блокировочном экране Android

Запись и чтение активности приложений iPhone
Приватность

Запись и чтение активности приложений iPhone

Как кадрировать видео на Android — Google Photos и Samsung
Руководство

Как кадрировать видео на Android — Google Photos и Samsung