...
multer 모듈
멀터는 사용 방법이 다소 어려운 미들웨어다.
이미지, 동영상 등을 비롯한 여러 가지 파일들을 멀티파트 형식으로 업로드할 때 사용하는 미들웨어이다.
멀티파트 형식이란 enctype이 multipart/form-data 인 폼을 통해 업로드하는 데이터의 형식을 의미한다.
먼저 multipart.html 파일을 다음과 같이 만들어 데이터를 업로드할 수 있도록 해보자.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<form action="/upload" method="post" enctype="multipart/form-data"> <!-- 멀티파트 폼 데이터 -->
<input type="file" name="image">
<input type="text" name="title">
<button type="submit">Submit</button>
</form>
</body>
</html>
multer 문법
이제 multer를 설치하고 사용해보자.
multer 패키지 안에는 여러 종류의 미들웨어가 들어있다.
- storage는 저장할 공간에 대한 정보. 디스크나 메모리 저장 가능.
- diskStorage는 하드디스크에 업로드 파일을 저장한다는 것
- destination은 저장할 경로
- filename은 저장할 파일명(파일명+날짜+확장자 형식)
- Limits는 파일 개수나 파일 사이즈를 제한할 수 있음.
const multer = require('multer');
const fs = require('fs');
try {
fs.readdirSync('uploads'); // 폴더 확인
} catch(err) {
console.error('uploads 폴더가 없습니다. 폴더를 생성합니다.');
fs.mkdirSync('uploads'); // 폴더 생성
}
const upload = multer({
storage: multer.diskStorage({ // 저장한공간 정보 : 하드디스크에 저장
destination(req, file, done) { // 저장 위치
done(null, 'uploads/'); // uploads라는 폴더 안에 저장
},
filename(req, file, done) { // 파일명을 어떤 이름으로 올릴지
const ext = path.extname(file.originalname); // 파일의 확장자
done(null, path.basename(file.originalname, ext) + Date.now() + ext); // 파일이름 + 날짜 + 확장자 이름으로 저장
}
}),
limits: { fileSize: 5 * 1024 * 1024 } // 5메가로 용량 제한
});
// => 이렇게 설정한 upload라는 객체를 뒤에 라우터에 장착하면 된다.
multer에 넣은 인수들은 다음과 같다.
먼저 storage 속성에 어디에 (destination) 어떤 이름으로 (filename) 저장할지를 넣었다.
두 함수의 req 매개변수에는 요청에 대한 정보, file 객체에는 업로드한 파일에 대한 정보가 있으며, done 매개변수는 함수이다.
done() 함수는 첫 번째 인수에는 에러가 있다면 에러를 넣고, 두 번째 인수에는 실제 경로나 파일 이름을 넣어주면 된다.
req나 file의 데이터를 가공해 done으로 넘기는 식이다.
현재 설정으로는 uploads라는 폴더에 [파일명 + 현재시간.확장자] 파일명으로 업로드하는 것을 볼 수 있다.
limits 속성에는 업로드에 대한 제한 사항을 걸어두었다.
위 예제에서는 파일 크기를 5MB (5 * 1024 * 1024 byte) 로 제한해두었다.
다만 위 설정을 실제로 활용하기 위해선 서버에 uploads 폴더가 꼭 존재해야 한다.
없다면 직접 만들어주거나, fs 모듈로 서버를 시작할 때 생성하는 방식이 있다.
upload.single()
설정이 끝난다면 위에서 선언해준 upload 객체 변수가 생기게 되는데, 이 안에 다양한 종류의 미들웨어가 존재한다.
파일을 하나만 업로드하는 경우에는 single 미들웨어를 사용한다.
upload 라는 객체는 위에서 multer설정한 변수이다.
// 단순 웹페이지 get요청 들어오면 html을 띄워준다.
app.get('/upload', (req, res) => {
res.sendFile(path.join(__dirname, 'multipart.html'));
}
// 위에서 설정한 upload 객체 변수를 라우터에 장착 한다.
// 이미지 업로드 같은 동작은 특정 라우터에만 일어나기 때문에, app.use()에는 장착하지 않는 편이다.
app.post('/upload', upload.single('image'), (req, res) => { // 'image'라는 이름은 multipart.html의 <input type="file" name="image"> 에서 폼데이터 이름으로 온 것이다.
// upload.single('image')의 업로드 정보가 req.file에 넣어진다.
// <input type="text" name="title"> 의 텍스트 정보가 req.body에 넣어진다.
console.log(req.file, req.body);
res.send('ok');
})
single 미들웨어를 라우터 미들웨어 앞에 넣어두면 multer 설정에 따라 파일 업로드 후 req.fiile 객체가 생성된다.
인수는 input 태그의 name이나 폼 데이터의 키와 일치하게 넣으면 된다.
업로드가 성공하면 결과는 req.file 객체 안에 들어간다.
req.body에는 파일이 아닌, input 텍스트 데이터인 title이 들어가있다.
req.file 객체는 다음과 같이 생겼다.
{
fieldname: 'img',
originalname: 'hello.png',
encoding: '7bit',
mimetype: 'image/png',
destination: 'uploads/',
filename: 'hello1567238581123.png',
path: 'uploads//hello1567238581123.png',
size: 44933
}
upload.array()
여러 파일을 업로드하는 경우엔 HTML의 input 태그에 multiple을 쓴다.
<form name="이 폼의 이름" action="이 데이터들을 받을 파일" method="post" enctype="multipart/form-data">
<input type='file' name='many' multiple/>
</form>
이 경우 미들웨어는 single 대신 array로 교체하면 된다.
이때 업로드 정보들은 배열로 저장되게 된다.
app.post('/upload', upload.array('many'), (req, res) => {
console.log(req.files); // 업로드 결과도 req.file 대신 req.files 배열에 들어간다
res.send('ok');
});
upload.field()
한번에 파일을 여러 개 업로드하는게 아닌, 따로따로 업로드를 여러개 한다면,
즉, input 태그나 폼 데이터의 키가 다른 경우엔 fields 미들웨어를 사용한다.
예를 들어 HTML 파일이 아래와 같을 경우,
<form action="/upload" method="post" enctype="multipart/form-data">
<input type="file" name="image1">
<input type="file" name="image2">
<input type="file" name="image3">
<input type="text" name="title">
<button type="submit">Submit</button>
</form>
이 경우엔 fields 미들웨어를 사용하고, 인수로 input 태그들의 name들을 각각 적는다.
name뿐만 아니라 limits도 설정할수있는데, 이미지를 5장까지만 넣는다라는 설정이다.
app.post('/upload',
upload.fields([{ name: 'image1', limits: 5 }, { name: 'image2' }, { name: 'image3' }]), // 배열 객체를 넣는다.
(req, res) => {
// 업로드 결과는 각각 req.files.image1, req.files.image2에 들어간다.
console.log(req.files.image1);
console.log(req.files.image2);
console.log(req.files.image3);
res.send('ok');
}
);
upload.none()
특수한 경우에, 파일이 아님에도 멀티파트 형식으로 업로드하는 경우가 있다.
new FormData()로 데이터를 보낼때도 있기 때문이다.
그 경우 none 미들웨어를 사용한다.
파일은 없지만 멀티파트 형식이기 때문에 함수가 따로 존재하는 것이다.
app.post('/upload', upload.none(), (req, res) => {
console.log(req.body.title); // 이 경우 파일을 업로드하지 않으므로 req.body만 존재한다.
res.send('ok');
});
# Reference
이 글이 좋으셨다면 구독 & 좋아요
여러분의 구독과 좋아요는
저자에게 큰 힘이 됩니다.