앞서 클라이언트에서 어떤 방식으로 이미지 데이터를 서버에 전송하는지 공부했다.
이제, multipart/form-data를 다루는 미들웨어를 소개하고 어떻게 이미지를 서버에 받고 활용할 수 있는지 알아본다.
이미지를 비롯해 클라이언트가 단순 텍스트 이외의 데이터를 요청할 때 적절한 응답을 위해 express에선 multer
라는 모듈을 제공한다.
npm 공식 홈페이지 multer 페이지에 따르면, 다음과 같이 multer를 설명한다.
파일 업로드를 위해 사용되는 multipart/form-data를 다루기 위한 node.js 의 미들웨어
(multipart/form-data)가 아닌 form 요청에선 동작하지 않습니다.
multer의 기본 사용 예시는 다음 세 가지이다.
const express = require('express');
const multer = require('multer');
const uploadFile = multer({dest: './uploads'});
const app = express();
app.post('/uploads',
uploadFile.single("profileImg"//클라이언트 input name element 이름),
(req, res, next) => {
// req.file에 profileImg라는 필드의 이미지 파일 정보가 담김.
// req.body에는 이미지 이외의 필드의 텍스트 정보가 담김.
})
module.exports = { uploadFiles };
const express = require('express');
const multer = require('multer');
const uploadFiles = multer({dest: './uploads'});
const app = express();
app.post('/uploads/photo',
uploadFiles.array('profileImg', 12//maxCount),
(req, res, next) => {
// req.files는 필드 내 req.file 정보가 maxCount 만큼 array에 담김.
// req.body에는 이미지 이외의 필드의 텍스트 정보가 담김.
})
module.exports = { uploadFiles };
const express = require('express');
const multer = require('multer');
const uploadFiles = multer({dest: './uploads'});
const app = express();
const cpUpload = uploadFiles.fields([
{ name: 'avatar', maxCount: 1 },
{ name: 'gallery', maxCount: 8 }
]);
app.post('/chosen-profile', cpUpload, (req, res, next) => {
// req.files는 (String -> Array) 객체
// 필드명은 객체의 key에, 파일 정보는 배열로 value에 저장.
// e.g.
// req.files['avatar'][0] -> File
// req.files['gallery'] -> Array
// req.body에는 이미지 이외의 필드의 텍스트 정보가 담김.
})
module.exports = { uploadFiles };
multipart 데이터가 담긴 클라이언트의 요청은 multer 미들웨어를 거치면 file이라는 객체를 프로퍼티로 갖게 된다.
file은 다음 프로퍼티를 갖고 있다.
위 예제처럼 multer({dest: './uploads'}) dest 옵션을 활용해 default로 제공되는 multer 기능만으로 파일을 저장할 수 있다.
그러나 multer는 여러 옵션 객체를 갖고, 이를 통해서 파일을 저장하는 방식을 개발자가 직접 지정할 수 있다.
const multer = require('multer');
const path = require("path");
const uploadFiles = multer({
storage: multer.diskStorage({
destination: (req, file, cb) => {
cb(null, "./uploads");
},
filename: (req, file, cb) => {
const ext = path.extname(file.originalname);
cb(null, path.basename(file.originalname, ext) + Date.now() + ext);
},
}),
});
module.exports = { uploadFiles };
destination 프로퍼티로 저장 경로를, filename으로 파일 이름을 지정할 수 있다. filename의 기본값은 아래와 같은 무작위 문자열이다.
파일 전체를 포함하는 buffer 방식을 따른다. (버퍼링 할 때 그 버퍼이다!!)
메모리 스토리지를 사용시, 매우 큰 사이즈의 파일을 업로드 하거나 많은 양의 비교적 작은 파일들을 매우 빠르게 업로드 하는 경우 응용 프로그램의 메모리 부족이 발생 할 수 있다.
각각의 밸류 중 세 번째 인자로 받는 콜백 함수의 두 번째 인자로 boolean을 받아 어느 파일을 업로드하거나 제어할지 필터링할 수 있따.
만약, 경로를 지정하지 않으면 파일은 디스크가 아닌 메모리에 저장될 것이다.