1. multer 란?
multer는 Express.js 애플리케이션에서 파일 업로드를 간편하게 처리할 수 있도록 도와주는 미들웨어이다. 특히 멀티파트 폼 데이터(multipart/form-data)를 파싱하여 서버 측에서 사용할 수 있게 해준다.
1.1. multer의 기본 개념
1.1.1. 멀티파트 폼 데이터
- HTML 폼을 통해 파일을 업로드할 때, 브라우저는 multipart/form-data 형식으로 서버에 전송한다.
- 일반적인 application/x-www-form-urlencoded와는 다르게, 파일 바이너리를 포함할 수 있으므로 특수한 파서가 필요하다.
1.1.2 multer의 역할
- **multer**는 **multipart/form-data**를 파싱하여, 텍스트 필드와 업로드된 파일을 req.body, req.file(단일 파일) 또는 req.files(다중 파일) 형태로 제공한다.
- 파일 저장에 대해 다양한 전략(메모리, 디스크, 커스텀 저장소 등)을 설정할 수 있다.
2. 설치
npm install multer
3. 주요 옵션 및 설정
3.1 저장소(Storage) 설정
- multer.diskStorage: 파일을 디스크에 저장.
- multer.memoryStorage: 파일을 메모리 버퍼에 저장.
- 커스텀 저장소: 원하는 저장소를 직접 구현할 수 있다.
const storage = multer.diskStorage({
destination: (req, file, cb) => {
cb(null, 'uploads/');
},
filename: (req, file, cb) => {
cb(null, Date.now() + path.extname(file.originalname));
}
});
const upload = multer({ storage: storage });
3.2 파일 필터링(fileFilter)
- 업로드 파일 유형을 제한하거나 확장자를 검증하는 기능을 제공한다.
const fileFilter = (req, file, cb) => {
if (file.mimetype === 'image/jpeg' || file.mimetype === 'image/png') {
cb(null, true);
} else {
cb(new Error('지원하지 않는 파일 형식입니다.'), false);
}
};
const upload = multer({ storage: storage, fileFilter: fileFilter });
3.3 업로드 제한(limits)
- 파일 크기(fileSize)와 같은 업로드 제한을 설정하여 보안을 강화할 수 있다.
const upload = multer({
storage: storage,
limits: { fileSize: 5 * 1024 * 1024 } // 최대 5MB
});
4. 멀티 파일 업로드 & 필드 처리
4.1 단일 파일 업로드
- upload.single('fieldname'): 특정 필드 이름으로 단일 파일 업로드.
app.post('/uploadSingle', upload.single('image'), (req, res) => {
// 파일 정보: req.file
res.send('단일 파일 업로드 완료');
});
4.2 다중 파일 업로드
- upload.array('fieldname', maxCount): 여러 파일을 업로드.
app.post('/uploadMultiple', upload.array('images', 3), (req, res) => {
// 파일 정보: req.files (배열)
res.send('다중 파일 업로드 완료');
});
4.3 여러 필드 처리
- upload.fields([{ name: 'image', maxCount: 1 }, { name: 'documents', maxCount: 2 }]):
- 여러 필드를 각각 다른 개수로 업로드.
app.post('/uploadFields', upload.fields([
{ name: 'image', maxCount: 1 },
{ name: 'documents', maxCount: 2 }
]), (req, res) => {
// req.files.image -> 단일 파일 배열
// req.files.documents -> 다중 파일 배열
res.send('여러 필드 업로드 완료');
});
5. 에러 처리
5.1 파일 크기 초과
- **limits.fileSize**를 초과하면, **multer**가 에러를 던집니다.
- 에러 핸들링 미들웨어에서 처리하거나, 라우트 내에서 처리해야 합니다.
app.post('/upload', upload.single('image'), (err, req, res, next) => {
if (err instanceof multer.MulterError && err.code === 'LIMIT_FILE_SIZE') {
return res.status(400).send('파일 크기가 너무 큽니다.');
}
next(err);
});
5.2 파일 형식 제한
- fileFilter에서 형식이 맞지 않으면 에러를 발생시킬 수 있습니다.
- 마찬가지로 에러 핸들링 미들웨어에서 처리 가능합니다.
6. 사용 예시
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>업로드 파일 없음</title>
</head>
<body>
<script>
alert("업로드할 파일이 비어있습니다!");
location.href = "/upload";
</script>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>에러 발생</title>
</head>
<body>
<script>
alert("이미지 파일만 업로드 가능합니다!");
location.href = "/upload";
</script>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>이미지 업로드 성공</title>
</head>
<body>
<script>
alert("이미지 업로드 성공!");
location.href = "/upload";
</script>
</body>
</html>
public에 포함된 emptyFiles.html, error.html, success.html 을 위와 같이 구성하였다.
const express = require('express');
const morgan = require('morgan');
const cookieParser = require('cookie-parser');
const session = require('express-session');
// const dotenv = require('dotenv');
const path = require('path');
// dotenv.config();
const app = express();
app.set('port', process.env.PORT || 3000);
app.use(morgan('dev'));
app.use('/', express.static(path.join(__dirname, 'public')));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
// app.use(cookieParser(process.env.COOKIE_SECRET));
app.use(session({
resave: false,
saveUninitialized: false,
// secret: process.env.COOKIE_SECRET,
secret: '1234',
cookie: {
httpOnly: true,
secure: false,
},
name: 'session-cookie',
}));
const multer = require('multer');
const fs = require('fs');
try {
fs.readdirSync('uploads');
} catch (error) {
console.error('uploads 폴더가 없어 uploads 폴더를 생성합니다.');
fs.mkdirSync('uploads');
}
const upload = multer({
storage: multer.diskStorage({
destination(req, file, done) {
done(null, 'uploads/');
},
filename(req, file, done) {
const ext = path.extname(file.originalname);
done(null, path.basename(file.originalname, ext) + Date.now() + ext);
},
}),
fileFilter: (req, file, done) => {
// 이미지 파일만 허용
if (/^image\/(jpeg|png|gif)$/.test(file.mimetype)) {
done(null, true);
} else {
done(new Error('이미지 파일만 업로드 가능합니다.'), false);
}
},
limits: { fileSize: 5 * 1024 * 1024 },
});
app.get('/upload', (req, res) => {
res.sendFile(path.join(__dirname, 'multipart.html'));
});
// app.post('/upload', upload.array('image'), (req, res) => {
// // console.log(req.file);
// console.dir(req.files);
// res.send('ok');
// });
app.post('/upload', (req, res) => {
upload.array('image')(req, res, (err) => {
if(err) {
// 에러 발생 시 -> error.html 응답
return res.sendFile(path.join(__dirname, 'public', 'error.html'));
}
if(!req.files || req.files.length == 0) {
return res.sendFile(path.join(__dirname, 'public', 'emptyFiles.html'));
}
// 성공 시
res.sendFile(path.join(__dirname, 'public', 'success.html'));
});
});
app.get('/', (req, res, next) => {
console.log('GET / 요청에서만 실행됩니다.');
next();
}, (req, res) => {
throw new Error('에러는 에러 처리 미들웨어로 갑니다.')
});
app.use((err, req, res, next) => {
console.error(err);
res.status(500).send(err.message);
});
app.listen(app.get('port'), () => {
console.log(app.get('port'), '번 포트에서 대기 중');
});
위의 코드에서 const upload 에 multer를 세팅한다.
브라우저에서 3000포트의 /upload 의 경로로 이동하면, app.get('/upload' ~~) 라우터가 실행되며 'multipart.html'이 실행되며 위 사진과 브라우저에 html을 렌더링한다. (클라이언트[브라우저] 에서는 get으로 multipart.html을 받아 렌더링함)
파일 선택 후 업로드 버튼을 누르면 app.post('/upload', ~~) 가 실행된다.
upload.array('image')(req, res, (err) => {
if(err) {
// 에러 발생 시 -> error.html 응답
return res.sendFile(path.join(__dirname, 'public', 'error.html'));
}
if(!req.files || req.files.length == 0) {
return res.sendFile(path.join(__dirname, 'public', 'emptyFiles.html'));
}
// 성공 시
res.sendFile(path.join(__dirname, 'public', 'success.html'));
});
upload.array 미들웨어를 호출하여 public 내에 있는 html들 중 하나를 실행하게 된다.
'Node.js' 카테고리의 다른 글
익스프레스 웹 서버 만들기 - 라우터 분리하기 (0) | 2025.01.15 |
---|---|
익스프레스 웹 서버 만들기 - dotenv (0) | 2025.01.15 |
익스프레스 웹 서버 만들기 - 미들웨어 확장법 (1) | 2025.01.14 |
익스프레스 웹 서버 만들기 - 미들웨어(session) (0) | 2025.01.14 |
익스프레스 웹 서버 만들기 - 미들웨어(express.static) (1) | 2025.01.14 |