multer
multer
요청 타입이 multeipart/form-data
인 경우 multer를 이용해 받을 수 있다.
설치하기
npm i multer
사용방법
multer
모듈을 임포트 해주고 미들웨어로 사용하기 위해 여러 설정을 해준다.
const multer = require('multer');
const path = require('path');
// 디렉토리 없을 경우 생성해주는 예외 처리
// (server listen 전 단계 이므로 동기식 코드로 해도 무방)
try {
fs.readdirSync('assets');
} catch (error) {
console.error('not exist directory.');
fs.mkdirSync('assets');
}
const upload = multer({
// 파일 저장 위치 (disk , memory 선택)
storage: multer.diskStorage({
destination: function (req, file, done) {
done(null, 'assets/');
},
filename: function (req, file, done) {
const ext = path.extname(file.originalname);
done(null, path.basename(file.originalname, ext) + Date.now() + ext);
}
}),
// 파일 허용 사이즈 (5 MB)
limits: { fileSize: 5 * 1024 * 1024 }
});
storage
에서 파일을 저장 할 경로와 이름을 설정 할 수 있는데, file
인수에서 다음 속성으로 파일 정보를 얻을 수 있다.
- fieldname : html 폼에 정의된 필드 명
- originalname : 사용자가 업로드 한 파일 명
- size : 파일 사이즈 (byte 단위)
- mimetyp : 파일 타입 (밈 타입)
{
"fieldname": "file",
"originalname": "jortu.png",
"encoding": "7bit",
"mimetype": "image/png",
"destination": "assets/",
"filename": "jortu1641367168859.png",
"path": "assets\\jortu1641367168859.png",
"size": 381172
}
파일 업로드를 사용 할 라우터에 미들웨어 함수로 붙이면 된다. 작성한 함수에 메서드로 single
을 붙이고 있는데 업로드 방식에 따라 메서드 체이닝이 다르다. single
메서드는 단일 파일로 전달 받을 때 사용한다.
app.post('/photo', upload.single('file'), function (req, res, next) {
//업로드 정보 확인
console.log(req.file);
res.send('upload success.');
});
웹브라우저에서 통신 되는지 확인하려고 input file 필드 한개를 주고 jQuery
로 확인해 보았다.
<body>
<h2>file upload Test</h2>
<hr>
<input type="file" name="file" id="uploadFile">
</body>
<script>
$(function () {
function uploadImage() {
const formData = new FormData();
formData.append('file', $('#uploadFile')[0].files[0]);
console.log(JSON.stringify($('#uploadFile')[0].files[0]));
$.ajax({
type: 'POST',
url: '/photo',
data: formData,
processData: false,
contentType: false,
success: function (json) {
console.log(JSON.stringify(json));
}
});
}
$('#uploadFile').change(function () {
return uploadImage();
})
});
</script>
multer 설정
multer 호출 시 4개의 속성으로 옵션 객체를 생성할 수 있다.
const upload = multer({
storage: multer.diskStorage({..}),
limits : {..},
fileFilter : function(req, file, cb){ //..code }
});
storage (dest)
파일 저장에 관련한 옵션이다. storage 또는 dest 속성으로 정의한다. destination
은 업로드 한 파일을 어디에 저장할 지 결정하고, filename
은 저장 할 파일의 이름을 결정한다. (만약 filename에 대한 설정이 없다면 랜덤한 파일 이름으로 저장된다고한다..)
multer.memoryStorage()
는 임시 메모리에 파일을 저장할 때 사용한다. 어떠한 설정도 필요가 없으며 용량이 많은 파일이나 다수의 파일을 업로드 하는 경우에는 메모리 부족이 발생할 수 있다. (주로 클라우드 서비스에 파일을 올릴 때 임시 보관 용도로 사용한다고 한다.)
const diskStorage = multer.diskStorage({
//물리 디스크
destination: function (req, file, done) {
done(null, '/path');
},
filename: function (req, file, done) {
done(null, file.fieldname + '-' + Date.now());
}
});
const memoryStorage = multer.memoryStorage(); //임시 메모리
const upload = multer({
storage: diskStorage
});
limits
파일 관련한 크기를 제어하는 속성이다. 단순히 파일 용량 뿐만 아니라 필드 이름에 대한 사이즈도 제어할 수 있다. 최대한 엄격하게 관리해야 혹시나 받을 수 있는 외부 공격에 대해 도움이 될 수 있다.
- fieldNameSize : 필드 이름 최대 값 (기본 : 100 Byte)
- fileSize : 파일 크기 최대 값 (기본 : 무제한)
- files : 파일 필드의 최대 갯수 (기본 : 무제한)
const upload = multer({
limit : {fileSize : 5,242,880} //5 * 1024 * 1024 (5MB)
});
fileFilter
파일의 유형을 필터링하는 속성이다. 함수 내에 file
인자를 통해서 허용 시킬 파일을 필터링 할 수 있다. 아래 예제는 이미지 형식인 파일들만 허용하는 예제이다.
const upload = multer({
fileFilter(req, file, done) {
if (file.mimetype.lastIndexOf('image') > -1) {
//파일 허용
done(null, true);
} else {
//파일 거부
done(null, false);
}
}
});
허용된 파일이 아니더라도 http 통신은 정상적으로 출력되기 때문에 명확한 오류를 표기하려면 직접 미들웨어 함수를 호출하면 된다.
const upload = multer({
fileFilter(req, file, done) {
if (file.mimetype.lastIndexOf('image') > -1) {
//파일 허용
done(null, true);
} else {
//파일 거부
done(null, false);
}
}
}).single('file');
app.post('/photo', function (req, res, next) {
upload(req, res, function error(error) {
if (error) {
res.status(500).send('허용된 파일이 아닙니다!');
return;
} else {
res.status(200).send('upload success');
}
});
});
API
multer 사용 시 4개의 메서드를 제공하는데 각각의 역할은 다음과 같다.
- single(filename) : 단일 파일에 대한 전달 요청 (위의 예제들)
- array(fieldname, maxcount) : 동일한 필드에 대해
multiple
속성이 적용된 파일들에 대한 전달 요청 (req.files에 배열 형태로 받을 수 있다.)<input type="file" name="file" id="uploadFile" multiple />
- fields(fields) : 필드가 정의된 여러 파일을 전달 받는다.
.array
와 마찬가지로 req.files에 저장된다.<input type="file" name="main-image" id="uploadFile" /> <input type="file" name="sub-image" id="uploadFile" />
fields
를 사용할 때는 객체 배열로 받아와야한다.app.post('/photo', upload.fields([{name : 'main-image1'}, {name : 'main-image2'}), function(req, res){ //code.. });