Mulitpart Form
형식의 데이터를Backend Server
에서 처리하기 위해 사용되는Middleware
Form
에서 전달하는 데이터는 크게 Text
, File
2가지로 구분할 수 있으며 app.js
파일에서는 다음과 같이 클라이언트 Text
데이터를 처리했다.
app.use(express.json()); // axios로 데이터 보낼 때
app.use(express.urlencoded({ extended: true })); // 일반 form을 보낼 때
하지만 File
(이미지, 동영상...등)과 같은 데이터를 처리하기 위해서는 추가로 Multer
라는 Middleware
를 사용해야 한다.
Multer
는 다양한 타입의 파일들을 Multipart
형식으로 업로드하는 Middleware
이다.
여기서 Multipart
형식이란 enctype
이 multipart/form-data
인 Form
을 통해 업로드하는 데이터의 형식을 의미한다.
<Form encType="multipart/form-data">
:
:
</Form>
클라이언트에서 서버로 Form Data
를 전송하는 방법은 크게 2가지가 있다.
Browser
에서Backend Server
로Form Data
를 한번에 전송하는 방식
Browser
에서Backend Server
로Form Data
를 나눠서 전송하는 방식
Form Data
를 한번에 전송하는 방식은 Backend Server
에서 데이터를 처리하기 편하지만, 한번에 전송하기 때문에 이미지 미리보기, 처리 시간이 오래 걸린다는 단점이 있다.
반면에 Form Data
를 나눠서 전송하는 방식(Multipart 방식
)은 이미지를 우선적으로 전송하여 서버에 업로드한 뒤 파일명만 Return
하기 때문에 서버쪽에서 전달받은 주소를 통해 위의 단점을 해결할 수 있다.
본 포스팅에서는 Multipart 방식
을 사용하여 설명해보겠다.
아래 npm명령어를 통해 Multer Middleware
를 설치한다.
npm i multer
일반적인 Middleware
는 app.js
에서 모든 라우터에 공통으로 적용한다.
하지만 Form
은 각각의 Form
마다 데이터 전송 방식, 데이터 형식...등이 달라 해당 라우터에 개별적으로 적용한다.
upload setting
에서는 파일의 저장위치를 설정한다.
const multer = require('multer'); // multer 불러오기
const fs = require('fs'); // fs모듈 불러오기
// file system을 조작하는 fs모듈로 uploads폴더 생성
try {
fs.accessSync('uploads'); // uploads파일이 존재하는지 확인
} catch (error) {
console.log('uploads 폴더가 존재하지 않아 생성합니다.');
fs.mkdirSync('uploads'); // uploads파일을 생성
}
const upload = multer({
storage: multer.diskStorage({ // 저장 위치 (diskStorage: 컴퓨터의 하드디스크)
destination(req, file, done) {
done(null, 'uploads'); // uploads폴더에 저장
},
Node.js
는 파일명이 중복되면 기존 파일을 덮어씌운다, 그래서 다음과 같이 파일명에 업로드날짜를 추가하여 이를 해결한다.
// routes.post.js
const multer = require('multer');
const path = require('path'); // path모듈 불러오기
const fs = require('fs');
try {
fs.accessSync('uploads');
} catch (error) {
console.log('uploads 폴더가 존재하지 않아 생성합니다.');
fs.mkdirSync('uploads');
}
const upload = multer({
storage: multer.diskStorage({
destination(req, file, done) {
done(null, 'uploads');
},
filename(req, file, done) { // 업로드파일.png
const ext = path.extname(file.originalname); // 확장자 추출(.png)
const basename = path.basename(file.originalname, ext); // 파일명 추출(업로드파일)
done(null, basename + '_' + new Date().getTime() + ext); // 파일명에 업로드날짜 추가(업로드파일_20220101.png)
},
}),
});
다음과 같이 업로드 파일의 크기를 설정한다.
// routes.post.js
const multer = require('multer');
const path = require('path');
const fs = require('fs');
try {
fs.accessSync('uploads');
} catch (error) {
console.log('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);
const basename = path.basename(file.originalname, ext);
done(null, basename + '_' + new Date().getTime() + ext);
},
}),
limits: { fileSize: 20 * 1024 * 1024 } // 파일 크기 제한(20MB)
});
// routes.post.js
// <input type='file' name='images' /> 클라이언트에서 이미지를 업로드
router.post('/images', isLoggedIn, upload.array('images'), async (req, res, next) => { // POST /post/images
console.log(req.files); // 업로드 정보
res.json(req.files.map((v) => v.filename)); // 파일명 전달
});
클라이언트에서 업로드한 이미지는 라우터의 upload.array('input name')
로 전달된다.
이후 위에서 설정한 upload setting
과정을 거친 뒤 라우터가 실행된다.
또한 업로드 타입에 맞게 다음과 같이 설정할 수 있다.
<input type='file' name='images' />
// input에서 업로드한 데이터가 text, json
upload.none()
// input에서 업로드한 데이터가 이미지 1장
upload.single('images')
// input에서 업로드한 데이터가 이미지 1장이상
upload.array('images')
<input type='file' name='images1' />
<input type='file' name='images2' />
// 다수의 input에서 업로드한 데이터
upload.fields([{ name: 'images1' }, { name: 'images2' }])
Express.Static
은 이미지나 텍스트 파일...등과 같은 정적인 파일을 서비스
정적 파일이란, Image
, CSS
, JavaScript
파일...등과 같이 직접 값에 변화를 주지 않는 이상 변하지 않는 파일을 의미한다.
Express.js
는 이러한 정적 파일들을 손쉽게 제공할 수 있게 Static
이라는 Middleware
를 제공한다.
Multer
를 사용해 처리한 업로드파일을 Browser
에서 출력하면 다음과 같이 Front Server
를 참조하고 있어 오류가 발생한다.
<input type='file' name='images' />
<div>
{imagePaths.map((v) => {
<img src={`http://localhost:3065/${v}`} />
})}
</div>
위 문제는 Express.static Middleware
를 사용하여 Express.js
가 Backend Server
의 업로드파일을 참조할 수 있게 하여 해결할 수 있다.
Static Middleware
는 Express.js
가 기본적으로 제공하는 기능으로 별도의 설치 없이 다음과 같이 사용할 수 있다.
// app.js
const path = require('path');
// '/'는 서버주소('localhost3065/')를 의미
// path.join을 통해 현재 디렉토리이름(back) + 'uploads'로 수정
app.use('/', express.static(path.join(__dirname, 'uploads')));
Node.js 공식문서
Node.js 교과서 - 조현영
React로 NodeBird SNS 만들기 - 제로초