Node.js 멀티파트 파일 업로드 처리 방법 정리

배경

관리자 대시보드에 상품 이미지 업로드 기능을 추가해야 했다. Express 기반 API 서버에서 멀티파트 폼 데이터를 받아 S3에 업로드하는 구조로 설계했다.

Multer 설정

const multer = require('multer');
const multerS3 = require('multer-s3');
const aws = require('aws-sdk');

const s3 = new aws.S3({
  accessKeyId: process.env.AWS_ACCESS_KEY,
  secretAccessKey: process.env.AWS_SECRET_KEY,
  region: 'ap-northeast-2'
});

const upload = multer({
  storage: multerS3({
    s3: s3,
    bucket: 'my-bucket',
    key: function (req, file, cb) {
      const timestamp = Date.now();
      cb(null, `images/${timestamp}-${file.originalname}`);
    }
  }),
  limits: { fileSize: 5 * 1024 * 1024 }, // 5MB
  fileFilter: function (req, file, cb) {
    if (!file.mimetype.startsWith('image/')) {
      return cb(new Error('이미지 파일만 업로드 가능합니다'));
    }
    cb(null, true);
  }
});

라우터 구현

router.post('/upload', upload.single('image'), (req, res) => {
  if (!req.file) {
    return res.status(400).json({ error: '파일이 없습니다' });
  }
  
  res.json({
    url: req.file.location,
    key: req.file.key
  });
});

router.post('/upload-multiple', upload.array('images', 5), (req, res) => {
  const urls = req.files.map(file => file.location);
  res.json({ urls });
});

에러 처리

multer 에러는 별도로 핸들링이 필요했다.

app.use((err, req, res, next) => {
  if (err instanceof multer.MulterError) {
    if (err.code === 'LIMIT_FILE_SIZE') {
      return res.status(400).json({ error: '파일 크기는 5MB를 초과할 수 없습니다' });
    }
  }
  next(err);
});

정리

multer-s3를 사용하면 메모리에 파일을 올리지 않고 스트림으로 바로 S3에 업로드할 수 있어 메모리 효율적이다. 파일 크기 제한과 타입 검증은 fileFilter와 limits 옵션으로 간단히 처리 가능했다.

Node.js 멀티파트 파일 업로드 처리 방법 정리